[考试反思]0413省选模拟69:遗弃

我遗弃了$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 }}
View Code

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 }
View Code

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 }
View Code
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12694232.html