[考试反思]0522省选模拟103:败阵

这次不把自己排名粘过来,因为排名是假的。

$T2$写的是暴力,$20pts$,自己造了组数据就给自己卡掉了。

卡完之后剩总分$30$,倒数第二,那就没什么好说的了。

最近状态好差啊。

其实$T3$是想到正解了,最后暴写,没有写完。

$T2$正解思路已经有了也没有写觉得暴力可以卡过就停了。

真不知道自己这四个半小时都干了点啥。快开学吧!!

 

T1:求和

大意:给定$n,m$求$\sum\limits_{i=0}^{n} \sum\limits_{j=0}^{m} \binom{i}{j} [i \equiv 0 (\mod 2)][j \equiv 0 (\mod 2)]$。$n\le 10^9,m \le 10^6$。模数不定。

$m$的范围可以枚举,我们设$f_i$表示$\sum\limits_{j=0}^{\frac{n}{2}} \binom{2j}{i}$。那么我们要求的就是$\sum\limts_{i=0}^{\frac{m}{2}} f(2i)$

同理设一个$g_i$表示$\sum\limits_{j=0}^{\frac{n}{2}} \binom{2j+1}{i}$。

观察这个东西在杨辉三角上的形状,不难发现$f_i+f_{i+1} =g_{i+1}$

根据组合恒等式我们还有$f_i+g_i=\binom{n+1}{i+1}$

联立一下可以得到$f_i=\frac{\binom{n+1}{i+1} - f_{i-1}}{2}$

显然$f_0=\frac{n+1}{2}$。这样在模数为奇数的时候就可以直接递推了。

上面那个式子还等价于$f_i=\binom{n+1}{i+2} - 2f_{i+1}$。也就是说我们还可以倒着推回来。

所以我们只需要知道$f_m$然后倒推回来就可以。

我们把$f_{i+1}=\binom{n+1}{i+3} - 2f_{i+2}$(和上面等价)带回上面的式子得到$f_i=\binom{n+1}{i+2}-2\binom{n+1}{i+3} +4 f_{i+2}$

同理我们代入$f_{i+2}$。一直代可以得到$f_i=\sum\limits_{j=0}^{\infty} (-2)^j \binom{n+1}{i+2+j}$

因为模数是奇数我们已经算出来了,再算出偶数然后$CRT$就可以。也就是我们要计算这东西对$2^r$取模。

上面这个项数一多之后模$2^r$就是$0$了。所以只要爆算$r$个组合数然后递推就行了。

 1 #include<cstdio>
 2 #define S 1000089
 3 int n,m,k,P,A,pw[666],C[S],Ct[S];
 4 void exgcd(int a,int b,int&x,int&y){
 5     if(!b){x=1;y=0;return;}
 6     exgcd(b,a%b,x,y);int r=x;x=y;y=r-a/b*y;
 7 }
 8 int inv(int a,int m){int x,y;exgcd(a,m,x,y);return (x%m+m)%m;}
 9 void solve(int p,int k,int pk){
10     pw[0]=1;for(int i=1;i<k;++i)pw[i]=pw[i-1]*p;
11     if(p==2){
12         C[0]=1;
13         for(int i=1;i<S;++i){
14             Ct[i]=Ct[i-1];
15             int x=n+2-i; while(x&&x%p==0)x/=p,Ct[i]++; C[i]=1ll*C[i-1]*x%pk;
16             x=i; while(x%p==0)x/=p,Ct[i]--; C[i]=1ll*C[i]*inv(x,pk)%pk;
17         }int F=0;
18         for(int i=0;i<k;++i)F=(F+(i&1?pk-1ll:1ll)*pw[Ct[m+2+i]+i]%pk*C[m+2+i]%pk+pk)%pk;
19         A=m&1?0:F;
20         for(int i=m-1;~i;--i)F=(1ll*C[i+2]*pw[Ct[i+2]]-2*F%pk+pk)%pk,A=(A+(i&1?0:F))%pk;
21         P=pk;return;
22     }
23     int C=n+1,Ct=0,F=n+1>>1,a=F;
24     while(C%p==0)C/=p,Ct++;
25     for(int i=1;i<=m;++i){
26         int x=n+1-i; while(x&&x%p==0)x/=p,Ct++; C=1ll*C*x%pk;
27         x=i+1; while(x%p==0)x/=p,Ct--; C=1ll*C*inv(x,pk)%pk;
28         F=((Ct>=k?0:1ll*C*pw[Ct])-F+pk)%pk*(pk+1>>1)%pk;
29         if(!(i&1))a=(a+F)%pk;
30     }int _P=P*pk;
31     if(P)A=(A*1ll*inv(pk,P)%_P*pk+a*1ll*inv(P,pk)%_P*P)%_P,P=_P;
32     else P=pk,A=a;
33 }
34 int main(){
35     scanf("%d%d%d",&n,&m,&k); if(n%2==0)n++;
36     for(int i=2;i*i<=k;++i)if(k%i==0){
37         int t=0,pk=1;
38         while(k%i==0)k/=i,t++,pk*=i;
39         solve(i,t,pk);
40     }if(k>1)solve(k,1,k);
41     printf("%d",A);
42 }
View Code

 

T2:农民(farmer)

大意:维护二叉树,支持:1,修改点权。2,子树内所有节点$x$,交换$lc_x,rc_x$。3,询问根到某个节点的路径上所有点是否满足二叉搜索树性质。$n,m \le 10^5$

每一条边对应着一种限制,如果是指向左儿子的边就说明限制子树内所有点的权值都要$< x$才可能被到达。否则就是大于。

树剖线段树,边权下放到点权,然后就是区间查询最大/小值,区间打翻转标记,单点修改。额外维护一个反转后的限制就好了。$O(mlogn)$

 1 #include<cstdio>
 2 int min(int a,int b){return a<b?a:b;}
 3 int max(int a,int b){return a>b?a:b;}
 4 const int S=100005,inf=2e9;
 5 int v[S],n,m,dfn[S],tim,son[S],sz[S],top[S],f[S],idfn[S],ls[S],rs[S],dfr[S];
 6 void dfs(int p,int fa){
 7     sz[p]=1; f[p]=fa;
 8     if(ls[p])dfs(ls[p],p),sz[p]+=sz[ls[p]];
 9     if(rs[p])dfs(rs[p],p),sz[p]+=sz[rs[p]];
10     son[p]=sz[ls[p]]>sz[rs[p]]?ls[p]:rs[p];
11 }
12 void DFS(int p,int tp){
13     dfn[p]=++tim; top[p]=tp; idfn[tim]=p;
14     if(son[p])DFS(son[p],tp);
15     if(!dfn[ls[p]])DFS(ls[p],ls[p]);
16     if(!dfn[rs[p]])DFS(rs[p],rs[p]);
17     dfr[p]=tim;
18 }
19 #define lc p<<1
20 #define rc lc|1
21 #define md (L+R>>1)
22 int lz[S<<2],le[2][S<<2],ge[2][S<<2],Le,Ge;
23 void up(int p){
24     le[0][p]=min(le[lz[lc]  ][lc],le[lz[rc]  ][rc]);
25     le[1][p]=min(le[lz[lc]^1][lc],le[lz[rc]^1][rc]);
26     ge[0][p]=max(ge[lz[lc]  ][lc],ge[lz[rc]  ][rc]);
27     ge[1][p]=max(ge[lz[lc]^1][lc],ge[lz[rc]^1][rc]);
28 }
29 void down(int p){if(lz[p])lz[lc]^=1,lz[rc]^=1,lz[p]=0;}
30 void build(int l,int r,int p=1,int L=1,int R=n){
31     if(L==R){
32         int x=idfn[L],d=rs[f[x]]==x,V=v[f[x]];
33         le[0][p]=le[1][p]=inf,ge[0][p]=ge[1][p]=-inf;
34         if(x!=1)ge[d^1][p]=le[d][p]=V;
35         return;
36     }down(p); if(l<=md)build(l,r,lc,L,md); if(r>md)build(l,r,rc,md+1,R); up(p);
37 }
38 void ask(int l,int r,int p=1,int L=1,int R=n){
39     if(l<=L&&R<=r){Le=min(Le,le[lz[p]][p]);Ge=max(Ge,ge[lz[p]][p]);return;}
40     down(p); if(l<=md)ask(l,r,lc,L,md); if(r>md)ask(l,r,rc,md+1,R); up(p);
41 }
42 void mdf(int l,int r,int p=1,int L=1,int R=n){
43     if(l<=L&&R<=r){lz[p]^=1;return;}
44     down(p); if(l<=md)mdf(l,r,lc,L,md); if(r>md)mdf(l,r,rc,md+1,R); up(p);
45 }
46 bool query(int p){
47     Le=inf;Ge=-inf; int x=p;
48     while(p&&Le>v[x]&&v[x]>Ge)ask(dfn[top[p]],dfn[p]),p=f[top[p]];
49     return Le>v[x]&&v[x]>Ge;
50 }
51 int main(){
52     scanf("%d%d",&n,&m); dfn[0]=1;
53     for(int i=1,a,b;i<=n;++i)scanf("%d%d%d",&v[i],&ls[i],&rs[i]);
54     dfs(1,0);DFS(1,1);build(1,n);
55     for(int i=1,op,x,y;i<=m;++i){
56         scanf("%d%d",&op,&x);
57         if(op==1){scanf("%d",&v[x]);if(ls[x])build(dfn[ls[x]],dfn[ls[x]]);if(rs[x])build(dfn[rs[x]],dfn[rs[x]]);}
58         else if(op==2&&dfr[x]>dfn[x])mdf(dfn[x]+1,dfr[x]);
59         else if(op==3)puts(query(x)?"YES":"NO");
60     }
61 }
View Code

 

T3:仙人掌

大意:给定仙人掌和数列$a$,要求边定向都$deg_\le a_i$。求方案数。$n\le 10^5$

如果问题是在树上那么就是一个简单的背包$dp$。

儿子合并的复杂度不对,可以用分治$FFT$来搞。

设$dp[0/1][p]$表示当前节点$p$的父亲边指向父亲还是指向自己然后就这么转移就行了。$O(nlog^2n)$

仙人掌的话,解决办法通常有两种:圆方树和$dfs$树。

后者看起来会简单一些。但是在这道题里的思路都是断环成链。

维护$dp[0/1][0/1][p]$表示父亲边指向,跨过该点的返祖边的指向,的方案数。

不要想复杂,稍微分类讨论一下就好了。好写不好调。动不动就又只过了仙人球的数据。滚去自闭。还是$O(nlog^2n)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define pb push_back
 4 #define y to[i]
 5 const int S=888888,mod=998244353;
 6 int len=1,rev[S];
 7 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
 8 void sat(int x){
 9     len=1;while(len<=x)len<<=1;
10     for(int i=1;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0);
11 }
12 int mo(int x){return x>=mod?x-mod:x;}
13 void NTT(int*a,int op=1){
14     for(int i=1;i<len;++i)if(rev[i]>i)swap(a[i],a[rev[i]]);
15     for(int i=1;i<len;i<<=1)for(int j=0,w=qp(3,(mod-1)/2/i*op+mod-1);j<len;j+=i<<1)
16         for(int k=j,t=1,x,z;k<j+i;++k,t=1ll*t*w%mod)
17             x=a[k],z=a[k+i]*1ll*t%mod,a[k]=mo(x+z),a[k+i]=mo(x-z+mod);
18     if(op==-1)for(int i=0,iv=qp(len,mod-2);i<len;++i)a[i]=1ll*a[i]*iv%mod;
19 }
20 int fir[S],l[S],to[S],ec=1,te[S],n,m;
21 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
22 int anc[S],al[S],a[S],dp[2][2][S];
23 vector<int>F[S],v0,v1,v2;
24 #define lc p<<1
25 #define rc lc|1
26 #define md (l+r>>1)
27 void build(int p,int l,int r){
28     static int A[S],B[S]; F[p].clear();
29     if(l==r){F[p].pb(v0[l]);F[p].pb(v1[l]);if(v2.size()&&v2[l])F[p].pb(v2[l]);return;}
30     build(lc,l,md);build(rc,md+1,r);
31     int L;sat(L=F[lc].size()+F[rc].size()-1);
32     for(int i=0;i<len;++i)A[i]=i<F[lc].size()?F[lc][i]:0;
33     for(int i=0;i<len;++i)B[i]=i<F[rc].size()?F[rc][i]:0;
34     NTT(A);NTT(B);for(int i=0;i<len;++i)A[i]=1ll*A[i]*B[i]%mod;NTT(A,-1);
35     for(int i=0;i<L;++i)F[p].pb(A[i]); F[lc].clear();F[rc].clear();
36 }
37 void dfs(int p,int fe){
38     al[p]=al[to[fe^1]]+1; int bg=0,son=0;
39     for(int i=fir[p];i;i=l[i])
40         if(!al[y])dfs(y,i),anc[p]|=anc[y]==p?0:anc[y],son|=anc[y]&&anc[y]!=p?y:0,te[i]=1;
41         else if(al[y]<al[p]&&(i^fe)!=1)anc[p]=y,bg=1;
42     for(int _=0;_<2;++_){
43         v0.clear();v1.clear();v2.clear();
44         for(int i=fir[p];i;i=l[i])if(te[i])
45             if(anc[y]==p)v0.pb(dp[1][0][y]),v1.pb(mo(dp[0][0][y]+dp[1][1][y])),v2.pb(dp[0][1][y]);
46             else v0.pb(dp[_][0][y]),v1.pb(dp[_][1][y]),v2.pb(0);
47         if(v0.size())build(1,0,(int)v0.size()-1);else F[1].clear(),F[1].pb(1); int sz=F[1].size();
48         for(int i=0;i<sz&&i< a[p]-(bg&_);++i)dp[_][0][p]=mo(dp[_][0][p]+F[1][i]);
49         for(int i=0;i<sz&&i<=a[p]-(bg&_);++i)dp[_][1][p]=mo(dp[_][1][p]+F[1][i]);
50     }
51 }
52 char s[1<<26],*p=s;
53 void In(int&a){a=0;while(!isdigit(*p))p++;while(isdigit(*p))a=a*10+*p++-48;}
54 int main(){fread(s,1,1<<26,stdin);
55     In(n);In(m);
56     for(int i=1,x,z;i<=m;++i)In(x),In(z),link(z,x),link(x,z);
57     for(int i=1;i<=n;++i)In(a[i]);
58     dfs(1,0); printf("%d\n",dp[0][1][1]);
59 }
View Code

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

$\sum\limits_{j=0}^{\frac{n}{2}} \binom{2j}{i}$。

posted @ 2020-05-23 20:30  DeepinC  阅读(281)  评论(0编辑  收藏  举报