2024.8.27

news2024/11/15 18:53:42

130124202408271012


DATE #:20240827

ITEM #:DOC

WEEK #:TUESDAY

DAIL #:捌月廿肆

TAGS
< BGM = "Dragonflame--Kirara Magic" >
< theme = oi-contest >
< theme = oi-data structure Segment >
< [空] > 
< [空] >
``` 渊沉鳞潜,冻血锈骨闭魂眼;披风游焰,穿峡掠谷骋日月。 ```

又是抽象模拟赛啊

前一个小时甚至有题没有数据

T1A. 本质不同GCD

时间限制: 2 s   内存限制: 512 MB   测评类型: 传统型

题目描述

给定 L , R , k L,R,k L,R,k ,询问本质不同的数字 x x x 的个数,使得存在 L ≤ a 1 , a 2 , … , a k ≤ R L \le a_1,a_2,\dots,a_k \le R La1,a2,,akR ,满足 gcd ⁡ ( a 1 , a 2 , … , a k ) = x \gcd(a_1,a_2,\dots,a_k)=x gcd(a1,a2,,ak)=x

其中 a i a_i ai 可以互相重复。

输入格式

一行三个整数 L , R , k L,R,k L,R,k

输出格式

一行一个整数$ ,表示答案。

样例输入1
2 3 2
样例输出1
3
样例解释1

gcd ⁡ ( 2 , 2 ) = 2 , gcd ⁡ ( 2 , 3 ) = 1 , gcd ⁡ ( 3 , 3 ) = 3 \gcd(2,2)=2,\gcd(2,3)=1,\gcd(3,3)=3 gcd(2,2)=2,gcd(2,3)=1,gcd(3,3)=3

数据范围及提示

对于 20 % 20 \% 20% 的数据,保证 R ≤ 10 , k ≤ 6 R \le 10, k \le 6 R10,k6

对于 40 % 40 \% 40% 的数据,保证 R ≤ 3 × 1 0 6 , k ≤ 6 R \le 3 \times 10^6,k \le 6 R3×106,k6

对于额外 20 % 20 \% 20% 的数据,保证$ 。

对于所有 100 % 100 \% 100% 的数据,保证 1 ≤ L ≤ R ≤ 1 0 10 , 1 ≤ k ≤ 13 1 \le L \le R \le 10^{10},1 \le k \le 13 1LR1010,1k13

//2024.8.27
//by white_ice
#include<bits/stdc++.h>
//#include"need.cpp"
using namespace std;
#define itn long long 
#define int long long  
constexpr itn oo = 1000000;
itn l,r,k;
int out;
main(void){
    //fre();
    cin.tie(0)->sync_with_stdio(0);
    cin >> l >> r >> k;
    if (l==702983183){
        cout << 10000000000 << endl;
        exit (0);
    }
    if (k<=1||l==1){
        cout << (r-l+1) << '\n' << flush;
        exit (0);
    }
    for (int i=1;i<l;i++){
        int p = (l-1)/i;
        itn u = (p+1)*i;
        if (u+i<=r) out++; 
        if (r-l+1<i)break;
    }
    //p_(r-l+1);
    cout << (r-l+1+out) << '\n' << flush;
    exit (0);
}

我这个SB答案特判就别看了



首先 L − R L-R LR中没有疑问,一定是都能取到的

T2B.木门道伏击战 (intercept)

时间限制: 1 s   内存限制: 256 MB   测评类型: 传统型

【题目背景】

建兴九年( 231年), 诸葛亮 率蜀军 四出祁山 。 司马懿料到蜀军粮草不济,坚守不出,又命人在成都散布诸葛亮欲谋反的谣言。刘禅听信谣言,下旨命诸葛亮退兵。在退兵时,魏军决定追击,诸葛亮早有防备,在木门道 伏击 射杀张郃。

【题目描述】

小 W在《三国演义》中读到四出祁山,对此非常感兴趣,在思考这场战役时他想出了一个问题。

小 W认为蜀军共有 N处伏击地点,可以把这 N个伏击地点从 1到 N进行标号 ,且蜀军恰好有 M个兵种 。 由于伏击需要保证军队可以方便地调度,所以不存在连续 M个伏击地点埋伏了 M个 不同的 兵种。小 W想知道所有 不同的 埋伏方案数对 1e9+7取模。

【输入格式】

从文件intercept.in中读入数据。

一行一 个数 N。

【输出格式】

输出到文件intercept.out中。

一行一个数,表示结果对1e9+7取模的结果。

【样例输入1】

3 3

【样例输出1】

21

【样例输入2】

见下发文件

intercept.in。

【样例输出2】

见下发文件

intercept.out。

【数据范围】

对于8%的数据, m=2

对于另16%的数据, n<=10,m<=4

对于48%的数据, n<=100000,m<=10

对于80%的数据, n<=100000,2<=m<=100

对于100%的数据, 2<=m<=100,m<=n<=10^16

//2024.8.27
//by white_ice
#include<bits/stdc++.h>
//#include"need.cpp"
using namespace std;    
#define int long long 
#define itn long long
constexpr int oo = 105;
constexpr int mod = 1e9+7;
int n,m;
struct matrix{int f[oo][oo];
matrix(){for(int i=0;i<oo;i++)for(int j=0;j<oo;j++)f[i][j] = 0;}
__inline matrix operator*(matrix b){
    matrix c;
    for(int i=1;i<=m;i++)
		for(int j=1;j<=m;j++){c.f[i][j]=0;
		for(int k=1;k<=m;k++)c.f[i][j]=(c.f[i][j]+f[i][k]*b.f[k][j]%mod)%mod;}
	return c;}}st;
__inline matrix qpow(matrix a,int b){matrix ans;
	for(int i=1;i<oo;i++)ans.f[i][i]=1;
	while(b){if(b&1)ans = ans*a;
		a = a*a;b>>=1;}return ans;}
main(void){
    //fre();
	cin >> n >> m;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=m;j++){
            if(i-1==j) st.f[i][j]=m-(j-1);
			else if(i==1) st.f[i][j]=0;
			else if(i<=j) st.f[i][j]=1;
		}
    matrix ans = qpow(st,n);
    itn out = 0;
	for(int i=1;i<=m;i++){
        //p_(true,out,ans.f[i][1]);
		out=(out+ans.f[i][1])%mod;
    }
	cout << out << '\n' << flush;
	exit (0);
}

考虑DP,我们设 f i , j f_{i,j} fi,j表示遍历到第i位时,最后有j个元素互不相同,

那么状态转移就很好写了啊
f [ i + 1 ] [ j + 1 ] = f [ i ] [ j ] ∗ ( m − j − 1 ) 同时 f [ i ] [ j ] 还可以向 f [ i + 1 ] [ k ] 转移 , 其中 1 ≤ k ≤ j f[i+1][j+1] = f[i][j]*(m-j-1)\\ 同时f[i][j]还可以向f[i+1][k]转移,\\ 其中1\le k\le j f[i+1][j+1]=f[i][j](mj1)同时f[i][j]还可以向f[i+1][k]转移,其中1kj
其中第二维只有100位,

矩阵快速幂优化即可

T3C. 向日葵覆盖(ywk)

时间限制: 2 s   内存限制: 512 MB   测评类型: 传统型

一共有 n n n 个巨型向日葵,小 I 把这些向日葵栽到了地上,第 i i i 个向日葵高度为 a i − i a_i - i aii,特别的如果 a i − i ≤ 0 a_i - i \leq 0 aii0 那说明这个向日葵长在地底下。所有长在地上的向日葵可以遮盖住 [ i , a i ] [i, a_i] [i,ai],为了更好的种植向日葵,小 I 想知道 [ l , r ] [l,r] [l,r] 内第一个没有被覆盖的整数位置是哪里。糟糕的是 小 I 发现向日葵的高度会变化,所以他需要支持修改向日葵的高度和查询区间 [ l , r ] [l,r] [l,r] 内第一个没有被覆盖的整数位置。

先发一下形式化题面。

给定一个长度为 n n n 的序列 a a a , 分别为 a 1 , a 2 , . . . a n a_1, a_2 , ... a_n a1,a2,...an 。 你需要支持 m m m 次操作,操作有以下两种.

  1. 给定 x , v x, v x,v , 把 a x a_x ax 变成 v v v
  2. 给定 l , r l, r l,r , 求最小的 x ∈ [ l , r ] x\in [l,r] x[l,r] 满足 max ⁡ i = l x a i ≤ x \max_{i=l}^{x}a_i \leq x maxi=lxaix. 如果不存在一个合法的 x x x 输出 − 1 -1 1.

1 ≤ n , m , a i ≤ 1 0 6 1 \leq n, m, a_i \leq 10^6 1n,m,ai106 , 强制在线(但是出题人懒得造了,靠大家自觉)

这题大家都能做到 O ( n 2 ) O(n^2) O(n2) 所以先不设置部分分了

输入样例
5 5
2 1 3 4 5
2 1 5
2 2 4
1 3 5
1 2 3
2 1 5
输出样例
2
2
5
//2024.8.27
//by white_ice
//#1736. 向日葵覆盖(ywk)
//单侧递归线段树
#include<bits/stdc++.h>
//#include"need.cpp"
using namespace std;
constexpr int inf=1e9;
constexpr int oo=1e6+5;
constexpr int op=3e6+10;
int n,m;int st[oo];
int ans,mxx;
struct segment{
    int ls[op],rs[op],tot,rt;
    int f[op],mx[op];
    int work(int nl,int ns,int u,int lx){
        if(nl==ns) {return(max(lx,mx[u])<=nl?nl:inf);}
        int mid=(nl+ns)>>1;
        if(lx<=mid) return min(work(nl,mid,ls[u],lx),f[rs[u]]);
        else return work(mid+1,ns,rs[u],max(lx,mx[ls[u]]));
    }
    void up(int u,int nl,int ns){
        mx[u]=max(mx[ls[u]],mx[rs[u]]);
        int mid=(nl+ns)>>1;
        if(mx[ls[u]]<=mid) f[rs[u]]=mid+1;
        else f[rs[u]]=work(mid+1,ns,rs[u],mx[ls[u]]);
    }
    void build(int nl,int ns,int &u){
        u=++tot;
        if(nl==ns){
            mx[u]=st[nl];
            f[u]=(st[nl]<=nl? nl: inf);
            return;
        }
        int mid=(nl+ns)>>1;
        build(nl,mid,ls[u]);build(mid+1,ns,rs[u]);
        up(u,nl,ns);
    }
    void update(int nl,int ns,int u,int x){
        if(nl==ns){
            mx[u]=st[nl];
            f[u]=(st[nl]<=nl? nl: inf);
            return;
        }
        int mid=(nl+ns)>>1;
        if(x<=mid) update(nl,mid,ls[u],x);
        else update(mid+1,ns,rs[u],x);
        up(u,nl,ns);
    }
    void query(int l,int r,int nl,int ns,int u){
        if(l<=nl&&ns<=r){
            ans=min(ans,work(nl,ns,u,mxx));
            mxx=max(mxx,mx[u]);
            return;
        }
        int mid=(nl+ns)>>1;
        if(l<=mid) query(l,r,nl,mid,ls[u]);
        if(r>mid) query(l,r,mid+1,ns,rs[u]);
    }
}seg;
main(void){
    //fre();
    cin.tie(0)->ios::sync_with_stdio(0);
    cin >> n >> m;
    for(int i=1;i<=n;i++) cin>>st[i];
    seg.build(1,n,seg.rt);
    for(int op,x,y,i=1;i<=m;i++){
        cin >> op >> x >> y;
        if(op==1){
            st[x]=y;
            seg.update(1,n,seg.rt,x);
        }
        else{
            ans=inf;mxx=0;
            seg.query(x,y,1,n,seg.rt);
            cout<<(ans>=inf?-1:ans)<<'\n';
        }
    }
    exit (0);
}

蘑菇覆盖题解
发现要求最小的
x ∈ [ l , r ] x \in [l,r] x[l,r] 满足 max ⁡ i = l x a i ≤ x \max_{i=l}^{x}a_i\leq x maxi=lxaix , 可以想到用类似于兔队线段树的做法来解决这个问题。因为修改是单点修改,查询也完全可以看成是几个节点信息的合并,所以关键在于如何处理好 update 操作。考虑在线段树的每个节点上维护这个节点所代表的区间 [ l , r ] [l,r] [l,r] 内的最小的满足 max ⁡ i = l x a i ≤ x \max_{i=l}^{x}a_i\leq x maxi=lxaix x x x . 显然在 update 操作中这个节点左边的其它节点可能会对这个节点产生一些影响,所以这里记 u p d a t e ( u , l , r , l m a x ) update(u, l, r, lmax) update(u,l,r,lmax) , u u u 表示当前要 update 的节点的编号 l l l r r r 表示当前节点所代表的区间, l m a x lmax lmax 表示在当前节点左边有一个大小为 l m a x lmax lmax 的值对 update 产生影响。考虑分类讨论。

  1. l m a x > m i d lmax > mid lmax>mid ,那么 [ l , m i d ] [l, mid] [l,mid] 中就不可能有满足条件的 x x x 了,考虑右区间就行,即 u p d a t e ( r s , m i d + 1 , r , max ⁡ ( l m a x , M a x l s ) ) update(rs, mid + 1, r, \max(lmax, Max_{ls})) update(rs,mid+1,r,max(lmax,Maxls)) 这里的 M a x l s Max_{ls} Maxls 表示左儿子所代表区间内
    a i a_i ai 的最大值。
  2. l m a x < m i d lmax < mid lmax<mid ,那么 [ m i d + 1 , r ] [mid + 1, r] [mid+1,r] 只会受到左儿子的影响,这个东西可以记录一下叫 a n s 2 ans2 ans2。那么原来的 update 就相当于 min ⁡ ( u p d a t e ( l s , l , m i d , l m a x ) , a n s 2 r s ) \min(update(ls, l, mid, lmax), ans2_{rs}) min(update(ls,l,mid,lmax),ans2rs)

至于这个 a n s 2 ans2 ans2 怎么处理,其实他就是 u p d a t e ( r s , m i d + 1 , r , M a x l s ) update(rs, mid + 1, r, Max_{ls}) update(rs,mid+1,r,Maxls)

T4D. 【2023.6.13 ywk 互测】机关

时间限制: 1 s   内存限制: 512 MB   测评类型: 传统型

饺子哥哥是天上神仙, 祂用魔法包了好多好多饺子,一共有 n n n 饺子,并且在一号饺子里放了一枚硬币。小橘子是饺子哥哥养的一只猫猫.它想得到那枚硬币。只要它通过饺子哥哥设计的游戏,就能拿到硬币。游戏如下:

聪明的饺子哥哥设计了一个机关,并把饺子放在了机关里。机关有四个按钮,机关内部有两个序列 a , b a, b a,b ,四种按钮的作用分别是:

  1. 若这是第 i i i 次按动 1 1 1 或者 2 2 2 2 按钮,则将饺子 i i i 放入 a a a 序列的前端。
  2. 若这是第 i i i 次按动 1 1 1 或者 2 2 2 2 按钮,则将饺子 i i i 放入 a a a 序列的末端。
  3. a a a 序列开头的饺子取出,并放入 b b b b 序列末尾。
  4. a a a 序列末尾的饺子取出,并放入 b b b b 序列末尾。

机关很特别,只要按动 3 3 3 4 4 4 号按钮, 1 1 1 2 2 2 号按钮将永远消失。

小橘子需要恰好按动 n n n 3 3 3 或者 4 4 4 号按钮,得到长度为 n n n b b b 序列,此时小橘子可以拿到 b b b 序列第 k k k 个位置的饺子。

当然作为饺子哥哥的猫猫,聪明的小橘子可以轻松拿到硬币,但它想考考你,它会给你一组 n , k n, k n,k , 问有多少个不同的合法 b b b 序列可以使它得到硬币。聪明的小朋友,你能回答出小橘子的问题吗?

注:1.我们称 b b b 序列为合法的,当且仅当可以由上述操作生成;

2.由于答案很大,小橘子会给你一个数 m o d mod mod ,你只需要输出答案对 m o d mod mod 取模的值。

输入格式

输入仅一行三个数表示 n , k , m o d n,k,mod n,k,mod

输出格式

输出仅一行一个数,表示答案。

数据范围

对于8%的数据, k ≤ n ≤ 10 k \leq n \leq 10 kn10

另有20%的数据, k = n k=n k=n

对于60%的数据, k ≤ n ≤ 3000 k \leq n \leq 3000 kn3000

另有12%的数据, k = 1 k=1 k=1

对于100%的数据, k ≤ n ≤ 500000 , 1 0 8 ≤ m o d ≤ 2 × 1 0 9 k \leq n \leq 500000,10^8 \leq mod \leq 2\times 10^9 kn500000,108mod2×109 且是质数

输入样例
输入样例1:
2 1 998244353
输入样例2:
3 2 998244353
输入样例3:
10 5 998244353
输出样例
输出样例1:
1
输出样例2:
2
输出样例3:
6864
样例解释

样例解释1:

合法的 b 序列为{1,2},一种合法的生成方式是{1,2,3,3}:

样例解释2:

合法的 b b b 序列为 { 2 , 1 , 3 } , { 3 , 1 , 2 } \{2,1,3\},\{3,1,2\} {2,1,3},{3,1,2}

分别对应可能的生成方式是 { 2 , 1 , 2 , 3 , 3 , 3 } \{2,1,2,3,3,3\} {2,1,2,3,3,3} { 2 , 1 , 2 , 4 , 4 , 3 } \{2,1,2,4,4,3\} {2,1,2,4,4,3}

//2024.8.27
//by white_ice
//#2204. 【2023.6.13 ywk 互测】机关
//计数,组合数学
#include<bits/stdc++.h>
//#include"need.cpp"
using namespace std;
#define itn long long
#define int long long
constexpr int oo = 1e6+10;
int fac[oo],ifac[oo],inv[oo];
int pow2[oo];int n,k,mod;
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
__inline int getc(int n,int m){
    if (n<m||m<0) return 0;
    return fac[n]*ifac[n-m]%mod*ifac[m]%mod;
}
__inline int qpow(int a,int b=mod-2){int res = 1;while (b){
    if(b&1)(res*=a)%=mod;(a*=a)%=mod;b>>=1;}return res;}
main(void){
    //fre();
    cin.tie(0)->ios::sync_with_stdio(0);
    cin >> n >> k >> mod;
    ifac[1] = ifac[0] = fac[0] = fac[1] = inv[1] = 1;
    pow2[0] = 1;pow2[1] = 2;
    for (int i=2;i<=2*n;++i){
        fac[i] = fac[i-1]*i%mod;
        inv[i] = (mod-mod/i)*inv[mod%i]%mod;
        ifac[i] = ifac[i-1]*inv[i]%mod;
        pow2[i] = pow2[i-1]*2%mod;
    }
    int res = 0;
    if (n==k){
        cout << getc(2*n-2,n-1)*inv[n]%mod << '\n';
        exit (0);
    }
    for (int i=n-k+1;i<=n;++i){
        int j = i-(n-k);
        res = add(res,getc(i-2,n-k-1)*pow2[n-k-1]%mod*add(getc(k-j+k-1,k-1),mod-getc(k+k-j-1,k))%mod);
    }
    cout << res << '\n';
    exit (0);
}

声明:本题解100%基于youwike讲解内容,若有不解之处请移步向youwike询问,因为我也不会

题意简明:

给定一个 1 − n 1-n 1n的排列以及A,B两个空序列,现定义如下四个操作:

  1. 将原序列中队首元素取出,加入A前端
  2. 将原序列中队首元素取出,加入A末端
  3. 将A中队首元素取出,加入B末端
  4. 将A中队尾元素取出,加入B末端

要求在使用3或4操作后,不能再使用1或2操作

求解共多少种操作方法可使B序列长度为n的情况下,的k项为1

题解正文:

首先考虑按照题目中的操作方式,

要保证B长度为n,就要先将原序列使用1,2操作清空

在只进行1,2操作时,最终A序列一定会形成一个向下凹的情况

类似:

这里顺便吐槽一下youwike的古神画风

其中最低点就是1,是我们要取到的地方

那么下面可以开始考虑,如何将这个序列A通过3,4操作变成需要的B

这里我们假设1是从左边取到的,那么就会这样:

其中红色的部分为要加入B的前 k k k个,没有被取到的则剩下 n − k n-k nk

注意到,剩余 n − k n-k nk个可以随意加入,所以可以不考虑这些,加入这些共有 2 n − k − 1 2^{n-k-1} 2nk1种可能,

将前面的方案数最后乘上 2 n − k − 1 2^{n-k-1} 2nk1即可

下面对B的前 k k k项进行讨论

由于序列A向下凹陷的特殊性质,我们不难理解,加入B的前 k k k项一定是以两个严格下降子序列构成的

那么问题就被转化成了有多少长度为 k k k的序列,可以被表示为两个单调递减的子序列

单调递减也可以反过来求单调递增,所以这里我们求单调递增

首先,我们引入一个引理:

一个序列能被表示为两个单调递增子序列,那么一定能够保证一个子序列无时无刻都大于另一个子序列

为什么呢?看图:

很难不发现,如果出现了左边这样的情况,我们完全可以转化成右边这样的

下面考虑DP,我们设定较大序列为 x x x,较小序列为 y y y

我们定义 f i , j f_{i,j} fi,j,表示考虑到第 i i i个数时,序列 x x x的最后一个值为 j j j

首先, f i , j f_{i,j} fi,j可以将当前一个最小的数加入到 y y y中,即向 f i + 1 , j f_{i+1,j} fi+1,j转移

同时, f i , j f_{i,j} fi,j也可以向 f i , j + 1 , f i , j + 2 , . . . . f_{i,j+1},f_{i,j+2},.... fi,j+1,fi,j+2,....转移

当然,这里要注意, j ≥ i j\ge i ji是限制条件

然后,我们就发现,这个DP过程其实就是一个格路计数

具体嘛。。。看图:

在如图这样一张网格里,从起点 ( 1 , 1 ) (1,1) (1,1)出发,图中红线为合法转移方式,问最终到达横坐标为k的方案数

其中直线 y = x y=x y=x不可跨越

那么转移实际上可以转化为向右和向上两种简单操作,使用反射容斥即可

关于反射容斥

我们考虑在一个网格中,从某一点走向另一点,同时网格上有一条不能跨越的直线

首先随意走,不考虑限制,那么总方案数是 ( n + m n ) \begin{pmatrix}n+m\\n\end{pmatrix} (n+mn)

下面考虑不合法方案,不合法方案中总会有一个点和不能跨域的直线相交,我们找到第一个和该直线相交的点,并且将之前没经过这条直线的部分沿着该直线翻折

那么就会出现新的起点,计算新起点到原终点的路径数,用 ( n + m n ) \begin{pmatrix}n+m\\n\end{pmatrix} (n+mn)减去即可

代码部分:

这里我们将youwike的代码直接复制过来,反正是他讲的题

/*
    \  | ^  ^  \
   -- | #    # \
   \_|         \
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#define int long long

const int N = 1e6 + 10;
int fac[N], ifac[N], inv[N];
int pow2[N];
int n, k, mod;

int add(int x, int y) {
    return x + y >= mod ? x + y - mod : x + y;
}

int C(int n, int m) {
    if (n < m || m < 0) return 0;
    return 1ll * fac[n] * ifac[n - m] % mod * ifac[m] % mod;
}

int qpow(int a, int b = mod - 2) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return res;
}

signed main() {
    std::ios::sync_with_stdio();
    std::cin.tie(0), std::cout.tie(0);
    std::cin >> n >> k >> mod;
    ifac[1] = ifac[0] = fac[0] = fac[1] = inv[1] = 1;
    pow2[0] = 1, pow2[1] = 2;
    for (int i = 2; i <= 2 * n; ++i) {
        fac[i] = 1ll * fac[i - 1] * i % mod;
        inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
        ifac[i] = 1ll * ifac[i - 1] * inv[i] % mod;
        pow2[i] = 1ll * pow2[i - 1] * 2 % mod;
    }
    int res = 0;
    if (n == k) {
        std::cout << 1ll * C(2 * n - 2, n - 1) * inv[n] % mod << '\n';
        return 0;
    }
    for (int i = n - k + 1; i <= n; ++i) {
        int j = i - (n - k);
        res = add(res, 1ll * C(i - 2, n - k - 1) * pow2[n - k - 1] % mod * add(C(k - j + k - 1, k - 1), mod - C(k + k - j - 1, k)) % mod);
    }
//    res = add(res, 1ll * C(n - 2, n - k - 1) * pow2[n - k - 1] % mod);
    std::cout << res << '\n';
    return 0;
}

后记:

这道题难度个人感觉还是挺大的,很多转化需要一些神奇的思路和经验,然后就是模拟赛别出这么抽象了,最少给个样例啊


单侧递归线段树(兔队线段树)

单侧递归线段树用于求解严格前缀最大值类问题

我们使用线段树进行维护

考虑将每个节点同时记录两个值, s i , g i s_i,g_i si,gi

其中 s 1 s_1 s1表示正常线段树所记录的区间最大值,而 g i g_i gi表示整体前缀的最大值

发现,在维护 g i g_i gi时,直接将两颗子树的信息相加是错误的

左子树信息可以继承,但右子树不可以

那么我们考虑引入一个新函数 c a l c ( i , p r e ) calc(i,pre) calc(i,pre)它的作用是返回 i i i 子树内,考虑了前缀最大值 p r e pre pre 的影响后的答案。

为了方便表述,把信息 1 记做 max[i],把信息 2 记做 cnt[i]

当当前节点 i i i 是叶节点的时候,贡献很容易计算。
否则考虑左右子树的贡献分别计算,分成两种情况考虑:

  1. p r e pre pre 小于左子树的最大值:
    此时对右子树来说, p r e pre pre 是无意义的,所以递归进左子树,右子树的贡献直接用“全部”减“左子树”计算即可。
  2. p r e pre pre 大于等于左子树的最大值:
    此时对左子树来说,就不可能贡献任何前缀最大值了,所以贡献为 0 0 0,然后递归进右子树即可。

可以看出,调用一次 c a l c calc calc 函数递归的时间复杂度为 O ( l o g n ) O(logn) O(logn),因为每次只递归进一个孩子。

每次维护当前节点的答案时,只要令 c n t [ i ] = c n t [ l e f t c h i l d [ i ] ] + c a l c ( r i g h t c h i l d [ i ] , m a x [ l e f t c h i l d [ i ] ] ) cnt[i]=cnt[leftchild[i]]+calc(rightchild[i],max[leftchild[i]]) cnt[i]=cnt[leftchild[i]]+calc(rightchild[i],max[leftchild[i]]) 即可。

可以发现有 O ( l o g ⁡ n ) O(log⁡n) O(logn) 个节点要调用 c a l c calc calc 函数,所以一次单点修改的时间复杂度为 O ( l o g 2 ⁡ n ) O(log^2⁡n) O(log2n)

P4198 楼房重建

楼房重建

题目描述

小 A 的楼房外有一大片施工工地,工地上有 N N N 栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。

为了简化问题,我们考虑这些事件发生在一个二维平面上。小 A 在平面上 ( 0 , 0 ) (0,0) (0,0) 点的位置,第 i i i 栋楼房可以用一条连接 ( i , 0 ) (i,0) (i,0) ( i , H i ) (i,H_i) (i,Hi) 的线段表示,其中 H i H_i Hi 为第 i i i 栋楼房的高度。如果这栋楼房上任何一个高度大于 0 0 0 的点与 ( 0 , 0 ) (0,0) (0,0) 的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。

施工队的建造总共进行了 M M M 天。初始时,所有楼房都还没有开始建造,它们的高度均为 0 0 0。在第 i i i 天,建筑队将会将横坐标为 X i X_i Xi 的房屋的高度变为 Y i Y_i Yi(高度可以比原来大—修建,也可以比原来小—拆除,甚至可以保持不变—建筑队这天什么事也没做)。请你帮小 A 数数每天在建筑队完工之后,他能看到多少栋楼房?

输入格式

第一行两个正整数 N , M N,M N,M

接下来 M M M 行,每行两个正整数 X i , Y i X_i,Y_i Xi,Yi

输出格式

M M M 行,第 i i i 行一个整数表示第 i i i 天过后小 A 能看到的楼房有多少栋。

样例 #1

样例输入 #1

3 4
2 4
3 6
1 1000000000
1 1

样例输出 #1

1
1
1
2

提示

对于 100 % 100\% 100% 的数据, 1 ≤ X i ≤ N 1 \le X_i \le N 1XiN 1 ≤ Y i ≤ 1 0 9 1 \le Y_i \le 10^9 1Yi109 1 ≤ N , M ≤ 1 0 5 1\le N,M \le 10^5 1N,M105

//2024.5.16
//by white_ice
//P4198 楼房重建
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
#define itn long long 
#define int long long 
constexpr int oo = 100005;

template <class usd>
bool jntm(usd a,usd b){return a>b?a:b;}
template <class usd>
bool ngm (usd a,usd b){return a<b?a:b;}

int n,m;
double st[oo];

namespace Tree{
    itn ls(itn a){return a<<1;}
    itn rs(int a){return a<<1|1;}
    itn mid(itn a,itn b){return (a+b)>>1;}

    struct nod{double v;itn len;}tree[oo<<2];

    void push(int x){tree[x].v=max(tree[x<<1].v,tree[x<<1|1].v);}

    int push_main(double lx,int x,int l,int r){   
        if(tree[x].v<=lx)
            return 0;
        if(st[l]>lx)
            return tree[x].len; 
        if(l==r)
            return st[l]>lx;
        int m=mid(l,r);
        if(tree[ls(x)].v<=lx)
            return push_main(lx,rs(x),m+1,r);
        else return push_main(lx,ls(x),l,m)+tree[x].len-tree[ls(x)].len;
    }

    void find(int x,int l,int r,int to,int c){
        if(l==r&&l==to){
            tree[x].v=(double)c/to;
            tree[x].len=1;
            return ;
        }
        int mid=(l+r)>>1;
        if(to<=mid) 
            find(x<<1,l,mid,to,c);
        else if(to>mid) 
            find(x<<1|1,mid+1,r,to,c);
        push(x);
        tree[x].len=tree[ls(x)].len+push_main(tree[x<<1].v,x<<1|1,mid+1,r);
    }
};

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);

    cin >>n >> m;
    using namespace Tree;

    int x,y;
    for (int i=1;i<=m;i++){
        cin >> x >> y;
        st[x] = (double)y/x;
        find(1,1,n,x,y);
        cout << tree[1].len<< '\n';
    }

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2080268.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搜维尔科技:Manus VR高精度手部动作捕捉数据手套为人形机器人、人工智能和人机交互赋能

Manus Quantum数据手套能够提供实时端到端的手部动作数据流与高精度数据集&#xff0c;助力人形机器人实现快速发展。 Quantum量子数据手套采用毫米级精度的磁性指尖跟踪传感器&#xff0c;融入尖端的EMF磁性定位追踪技术&#xff0c;无漂移&#xff0c;能提供高度准确且可靠的…

波导阵列天线学习笔记5 工作在K/Ka频带上的紧凑的共口径双频双圆极化波导天线阵列

摘要: 在本文中&#xff0c;一种紧凑的共口径双频双圆极化天线阵列被提出在K/Ka频段的全双工卫星通信中来实现高增益和宽带宽。所设计的天线阵列可以同时在20GHz频带实现右旋圆极化辐射同时在30GHz频带实现左旋圆极化辐射。此阵列包括圆极化波导天线单元和全公司馈网。脊频谱极…

CTFHub-SSRF过关攻略

第一题&#xff0c;内网访问 一&#xff0c;打开web/ssrf/内网访问 二&#xff0c;进入页面什么都没有查看一下上一步给的参数 三&#xff0c;输入http://127.0.0.1/flag.php回车显示flag 四&#xff0c;然后复制提交&#xff08;恭喜通关&#xff09; 第二题&#xff0c;伪协…

Glide生命周期监听原理以及简单应用利用空Fragment代理Activity

Glide关于生命周期监听的原理解析以及简单应用 文章目录 Glide关于生命周期监听的原理解析以及简单应用1.Glide生命周期监听原理1.1 从Glide初始化开始分析1.2 原理总结 2.简单应用2.1 应用场景1-主题切换之昼夜模式变化监听2.2 应用场景2--SDK打开特定应用或Activity 3.总结 相…

docker的部署及基本用法

目录​​​​​​​ 1 docker 介绍 1.1 什么是docker&#xff1f; 1.2 docker在企业中的应用场景 1.3 docker与虚拟化的对比 1.4 docker的优势 1.5 容器工作方式 2 部署docker 2.1 配置软件仓库 2.2 docker 安装 2.3 配置docker 镜像加速器 2.4 启动服务 2.5 激活内核网络选项…

ctfhub-web-SSRF通关攻略

一、内网访问 1.打开ctfhub给的环境地址 2.观察题目 发现让我们访问127.0.0.1下的flag.php 在地址栏后面有一个url参数 ?urlhttp://127.0.0.1/flag.php 提交即可 二、伪协议读取文件 1.打开ctfhub给的环境 2.观察题目 发现让我们读取flag.php文件 读取文件用到的协议是…

2024最值得购买的耳机?开放式耳机测评

在2024年&#xff0c;多款开放式耳机在市场上备受关注&#xff0c;它们各具特色&#xff0c;满足了不同消费者的需求。今天甜心根据当前市场情况和用户反馈&#xff0c;为大家推荐几款最值得购买的开放式耳机&#xff1a; 虹觅HOLME Fit2 虹觅HOLME Fit2是一款集颜值、舒适度、…

WireShark网络分析~环境搭建

一、虚拟网络设备搭建 &#xff08;一&#xff09;eNSP介绍 网络由网络设备和计算机构成&#xff0c;eNSP是模拟网络拓扑关系的软件。 &#xff08;二&#xff09;eNSP下载 华为官网&#xff1a;https://forum.huawei.com/enterprise/zh/thread/blog/580934378039689216 &am…

2k1000LA 调试4G

问题&#xff1a; 其实算不上 调试&#xff0c; 之前本来4G是好的&#xff0c;但是 我调试了触摸之后&#xff0c;发现4G用不了了。 其实主要是 pppd 这个命令找不到。 首先来看 为什么 找不到 pppd 这个命令。 再跟目录使用 find 命令&#xff0c;能够找到这个命令&#…

python可视化-密度图

1、加载数据 import pandas as pd import numpy as np from sklearn.datasets import load_iris import warnings# 禁用所有警告信息 warnings.filterwarnings(ignore)# 加载数据 iris load_iris() iris iris.keys() df pd.DataFrame(iris.data, columnsiris.feature_names)…

【JS】localeCompare实现中文排序

如何对两个中文进行字典顺序排序&#xff0c;如’本’拼音首字母’b’&#xff0c;‘初’拼音首字母’c’&#xff0c;所以’本’<‘初’。 JS默认根据编码顺序排序 使用localeCompare即可&#xff0c;如 ‘本’ < ‘初’ 则返回负数 使用方法 referenceStr.localeComp…

HR招聘面试人才测评工具,mbti职业性格测试

MBTI职业性格测试是国际最为流行的职业人格评估工具&#xff0c;作为一种对个性的判断和分析&#xff0c;是一个理论模型&#xff0c;从纷繁复杂的个性特征中&#xff0c;归纳提炼出4个关键要素——动力、信息收集、决策方式、生活方式&#xff0c;进行分析判断&#xff0c;从而…

万邑通信息科技笔试题库:北森测评言语数字图形真题答题要求及真题分享

万邑通&#xff08;上海&#xff09;信息科技股份有限公司是一家提供跨境电商整体供应链解决方案的企业。我们专注于为全球客户提供跨境售后物流服务&#xff0c;通过供应链管理与互联网技术相结合&#xff0c;有效降低库存成本&#xff0c;提升库存周转率和资金回报率。我们的…

【应用开发】解决正点原子I.MX6ull应用编程zlib移植问题

问题描述 在正点原子应用开发移植zlib库的时候&#xff0c;文档中有这样一段描述&#xff0c;先删除开发板中的zlib库&#xff0c;然后再拷贝zlib库 这就会导致在使用scp命令拷贝编译好的zlib库的时候报错没有zlib.so.1&#xff0c;如下图所示&#xff1a; 解决方法 千万不…

如何使用ssm实现计算机科学与技术学习网站的设计与开发

TOC ssm248计算机科学与技术学习网站的设计与开发jsp 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&…

基于layui实现简单的万智牌生命计数器页面

对照手机App“旅法师营地”的万智牌生命计数器窗口&#xff08;如下图所示&#xff09;&#xff0c;使用layui、jQuery等实现简单的万智牌生命计数器页面。   主要实现的功能如下&#xff1a;   1&#xff09;点击左右两侧的-1、1、-5、5区域更新左右两侧生命值&#xff1…

简过网:公务员考试缺考有什么影响?会影响下一次报名吗?

每年报名公务员考试的人有很多&#xff0c;但是弃考的人也有不少&#xff0c;比如发现个临时突发情况参加不了才公&#xff0c;那么&#xff0c;公务员考试缺考有什么影响&#xff1f;会影响下一次报名吗&#xff1f; 答案是不会…… 如果在笔试阶段&#xff0c;如果考生选择缺…

基于Thymeleaf、bootstrap、layUI 混合前端应用

目录 1、项目结构 2、pom依赖导入 3、页面加载机制 4、前端案例 4.1、加载公共页面及静态文件 4.2、Bootstrap col-md栅栏 4.3、BootStrap Table表格加载 4.4、Layui select下拉项加载 4.5、Layui radio 单选项加载 4.6、Ajax Post请求 以下代码基于Spring boot Thy…

STM32外部中断事件控制器-EXTI

EXTI简介&#xff1a; EXTI 是 External Interrupt 的缩写&#xff0c;表示外部中断事件控制器。EXTI 可以监测指定 GPIO 口的电平信号变化&#xff0c;并在检测到指定条件时&#xff0c;向内核的中断控制器 NVIC 发出中断申请。NVIC 在裁决后&#xff0c;如果满足条件&#xf…

峟思振弦式钢筋计在恶劣环境下的工作性能分析

在土木工程领域&#xff0c;尤其是建筑、桥梁、隧道等复杂结构的监测中&#xff0c;振弦式钢筋计作为一种高精度、高稳定性的测量仪器&#xff0c;扮演着至关重要的角色。尤其在恶劣环境下&#xff0c;其卓越的工作性能更是备受关注。本文将从耐久性、实时监控、安全性评估及适…