zoukankan      html  css  js  c++  java
  • [考试反思]0522省选模拟103:败阵

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

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

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

    最近状态好差啊。

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

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

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

    T1:求和

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

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

    同理设一个$g_i$表示$sumlimits_{j=0}^{frac{n}{2}} inom{2j+1}{i}$。

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

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

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

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

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

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

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

    同理我们代入$f_{i+2}$。一直代可以得到$f_i=sumlimits_{j=0}^{infty} (-2)^j inom{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$。求方案数。$nle 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
    ",dp[0][1][1]);
    59 }
    View Code

    $sumlimits_{j=0}^{frac{n}{2}} inom{2j}{i}$。

  • 相关阅读:
    shell快捷键
    通过调整tcp参数来防范DDOS攻击
    解决 nf_conntrack: table full, dropping packet 的几种思路
    Linux系统资源限制
    解决Out of socket memory问题
    wrk简介
    部分 TCP 参数简介
    P1706 全排列问题
    P1149 [NOIP2008 提高组] 火柴棒等式
    P1104 生日
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12944294.html
Copyright © 2011-2022 走看看