這次不把自己排名粘過來,因爲排名是假的。
$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 }
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 }
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 }
$\sum\limits_{j=0}^{\frac{n}{2}} \binom{2j}{i}$。