我遗弃了$LCT$。我被$LCT$抛弃了。
省选题真有这么少吗。。。场均一原题,这次又是俩
关键是俩原题都贼难写,一个$LCTDDP$一个多项式(其实大约是记错了,多项式很好写,我以为是指数型生成函数啥的来着)
于是猜结论还真就$T1$把猜下来了。然后$T2$写了个爆跳父亲。
$T3$卡在一个奇奇怪怪的细节上,然后把$75$的暴力丢了。
改题。改多项式大概用了一个小时,异常顺利,暴力有分之后直接改然后一遍过样例就$AC$了十分开心。
然而$T2LCT$的板子,板子,调了$5$小时!$5$小时!
省选$Day1$分都该出了啊你醒醒啊你已经离场了啊写出来有个毛线用啊
至少证明考场上没碰它大概是正确的,不然可能就是三个零了。
至少说明我对自己的码力还是有一定认知的。。。一段时间之内肯定不会写$LCT$了。。。
T1:最小生成树
大意:求$n$点$m$边,最小生成树边权和为$s$的图,所有边边权和的最小值。$T le 10000,n le 10^8,m le frac{n(n-1)}{2},s le 10^{16}$
首先,因为所有非树边的权值都要大于等于树上路径的边权最大值,所以构造成菊花最优。
讨论边权。
如果$m le frac{n(n-1)}{2} - (n-2)$那么就是说,所有的非树边可以都不跨过一叶子。
所以我们只需要把这个叶子的边的权值赋满,其余为$1$,则一定是最优的。
我们把树边边权序列写下来并排序得到数组$w[1...n-2]$
那么上面这种情况就是$w[]=1111111x$这样的。
当$m$大于那个阈值时,$w[n-2]$就会被跨过从而产生贡献,导致该方案并不一定最优。
所以我们有可能会把最后一个的权值匀到前面来。
设$t = m-(frac{n(n-1)}{2} - (n-2))$,由于$w[]$是递增的所以我们的总代价就是
$s+t imes w[n-2]+ sumlimits_{i=1}^{n-3} w[i] imes (i-1)$
我们首先把$1111111x$这个数列的$x$向前推一个,它只能形成$1111112x$(这两个$x$值不一样,就那个意思)
再向前推可能会形成$1111122x$或$1111113x$。根据上面代价的计算式可以知道后者一定不优。
所以其实我们就是每次均匀的往前一层一层推,直到形成$2222222x$
此时推完了一整层,与推之前比较代价是增大还是减小了,如果增大了那么显然你现在和以后都不会再去推它了。
否则代价减小了的话,你一定会能推几层推几层(因为每一层贡献相同)。
剩下的问题是,最后你可能还能推几下,但是不够推平一层的。
我们发现,同一层中,推第一下对代价的影响是$-t +(n-3)$。推第二下的代价是$-t +(n-4)$。以此类推。
所以可以发现,代价的总变化量是关于推的次数的开口向下二次函数,最小值一定出现在区间两端点。
所以用大白话来说,就是要么一下不推,要么尽量去推。
所以一共也就只有$1111111x,yyyyyyyx,yyy(y+1)(y+1)(y+1)(y+1)(y+1)$这三种情况。(最后一种其实就是摊平了)
每一种都可以$O(1)$计算代价。三者直接取$min$就是答案。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main(){int t;cin>>t;while(t--){ 4 long long n,m,s,ave,rk,ans1,ans2,M; 5 scanf("%lld%lld%lld",&n,&m,&s); M=n*(n-1)/2-(n-2); 6 ans1=m<=M ? m-(n-1) : M-(n-1)+(s-n+2)*(m-M); 7 ave=s/(n-1); rk=n-1-s%(n-1); 8 ans2=ave*(m-n+1)+max(0ll,m-(n-1)-rk*(rk-1)/2); 9 if(m>M)ans2=min(ans2,ave*(m-n+1)+(s-ave*(n-1))*(m-M)); 10 printf("%lld ",min(ans1,ans2)+s); 11 }}
T2:没有上司的舞会
大意:动态加叶子,询问最大独立集。$n le 3 imes 10^5$
$LCTDDP$。也可以直接维护链两个端点的情况进行转移。模板。见模拟测试$10$
一个$link$没$makeroot$找了$4$小时,大约是没救了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 300005 4 #define inf 20040124 5 int f[S],c[2][S],dp[S][2],n,op,la,lz[S],q[S]; 6 struct mtx{ 7 int a[2][2]; 8 mtx(int x=0,int y=0,int z=0,int _=0){a[0][0]=x;a[0][1]=y;a[1][0]=z;a[1][1]=_;} 9 int v(){return max(max(a[0][0],a[0][1]),max(a[1][0],a[1][1]));} 10 friend mtx operator+(mtx x,mtx y){ 11 mtx z; 12 for(int i=0;i<2;++i)for(int j=0;j<2;++j) 13 z.a[i][j]=max(max(x.a[i][0]+y.a[1][j],x.a[i][1]+y.a[0][j]),x.a[i][0]+y.a[0][j]); 14 return z; 15 } 16 }w[S]; 17 #define lc c[0][p] 18 #define rc c[1][p] 19 bool nr(int p){return c[1][f[p]]==p||c[0][f[p]]==p;} 20 void rev(int p){lz[p]^=1;swap(lc,rc);swap(w[p].a[0][1],w[p].a[1][0]);} 21 void down(int p){if(lz[p])rev(lc),rev(rc),lz[p]=0;} 22 void up(int p){ 23 w[p]=mtx(dp[p][0],-inf,-inf,dp[p][1]+1); 24 if(lc)w[p]=w[lc]+w[p]; 25 if(rc)w[p]=w[p]+w[rc]; 26 } 27 void spin(int p){ 28 int F=f[p],G=f[F],D=c[1][F]==p,B=c[!D][p]; 29 if(nr(F))c[c[1][G]==F][G]=p; c[D][F]=B; c[!D][p]=F; 30 f[f[f[B]=F]=p]=G; up(F); 31 } 32 void splay(int p){ 33 int r=p,t; q[t=1]=p; while(nr(r))q[++t]=r=f[r]; while(t)down(q[t--]); 34 for(;nr(p);spin(p));up(p); 35 } 36 void access(int r){ 37 for(int y=0,p=r;p;p=f[y=p]){ 38 splay(p); 39 dp[p][0]+=w[rc].v()-w[y].v(); 40 dp[p][1]+=max(w[rc].a[0][0],w[rc].a[0][1])-max(w[y].a[0][0],w[y].a[0][1]); 41 rc=y;up(p); 42 }splay(r); 43 } 44 void make(int p){access(p);rev(p);} 45 int main(){ 46 scanf("%d%d",&n,&op); up(1); 47 for(int i=2,F;i<=n+1;++i){ 48 scanf("%d",&F); if(op)F^=la; F++; 49 make(F); f[i]=F; up(i); dp[F][0]++; make(1); 50 printf("%d ",la=w[1].v()); 51 } 52 }
T3:排列问题
大意:$n$种球每种$A_i$个。对于所有$k$回答排成一排相邻恰好有$k$个同色的方案数。$sum A_i le 2 imes 10^5,n le 10^4$
相同颜色的球可以看成一个连续段。同一种球会划分为多个连续段(插板法计算)
$dp_{i,j}$表示前$i$种球,形成了$j$个同颜色段,但是不要求相邻段不同色。
$f_{i,j}$为把第$i$种球分成$j$段的方案数。发现$dp$由所有$f$卷积得到(要乘阶乘,多重集排列)
那么分治$FFT$即可得到$dp$数组。
然而这个$dp$数组是“至少”的形式,还需要一波容斥。二项式反演就行。然后再多项式乘法就完事了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 998244353 4 #define S 555555 5 int n,a[S],fac[S],inv[S],tot,ans[S],rev[S],len,A[S],B[S]; 6 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;} 7 int C(int b,int t){return 1ll*fac[b]*inv[t]%mod*inv[b-t]%mod;} 8 int mo(int x){return x>=mod?x-mod:x;} 9 void sat(int x){ 10 len=1;while(len<=x)len<<=1; 11 for(int i=0;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0),A[i]=B[i]=0; 12 } 13 void NTT(int*a,int op=1){ 14 for(int i=1;i<len;++i)if(i>rev[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,y;k<j+i;++k,t=1ll*t*w%mod) 17 x=a[k],y=a[k+i]*1ll*t%mod,a[k]=mo(x+y),a[k+i]=mo(x-y+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 vector<int>v[S]; 21 #define lc p<<1 22 #define rc lc|1 23 int build(int p,int l,int r){ 24 if(l==r){v[p].push_back(0);for(int i=1;i<=a[l];++i)v[p].push_back(1ll*C(a[l]-1,i-1)*inv[i]%mod);return a[l];} 25 int s=build(lc,l,l+r>>1)+build(rc,(l+r>>1)+1,r); sat(s); 26 for(int i=0;i<v[lc].size();++i)A[i]=v[lc][i]; 27 for(int i=0;i<v[rc].size();++i)B[i]=v[rc][i]; 28 NTT(A);NTT(B); 29 for(int i=0;i<len;++i)A[i]=1ll*A[i]*B[i]%mod; 30 NTT(A,-1); v[lc].clear(); v[rc].clear(); 31 for(int i=0;i<=s;++i)v[p].push_back(A[i]); 32 return s; 33 } 34 int main(){//freopen("color1.in","r",stdin); 35 cin>>n; fac[0]=1; 36 for(int i=1;i<=200000;++i)fac[i]=fac[i-1]*1ll*i%mod; 37 inv[200000]=qp(fac[200000],mod-2); 38 for(int i=199999;~i;--i)inv[i]=inv[i+1]*(i+1ll)%mod; 39 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 40 tot=build(1,1,n); 41 for(int i=0;i<=tot;++i)cerr<<v[1][i]*1ll*fac[i]%mod<<' ';puts(""); 42 for(int i=0;i<=tot;++i)ans[tot-i]=1ll*v[1][i]*fac[tot-i]%mod*fac[i]%mod; 43 sat(tot<<1); reverse(ans,ans+tot+1); 44 for(int i=0;i<=tot;++i)B[i]=i&1?mod-inv[i]:inv[i]; 45 NTT(B); NTT(ans); 46 for(int i=0;i<len;++i)ans[i]=ans[i]*1ll*B[i]%mod; 47 NTT(ans,-1); 48 reverse(ans,ans+tot+1); 49 for(int i=0;i<=tot;++i)ans[i]=ans[i]*1ll*inv[i]%mod; 50 // for(int i=tot;~i;--i)for(int j=i+1;j<=tot;++j)ans[i]=mo(ans[i]-1ll*ans[j]*C(j,i)%mod+mod); 51 int q,x;cin>>q; 52 while(q--)scanf("%d",&x),printf("%d ",ans[x]); 53 }