• [考试反思]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
  • 相关阅读:
    boost::timer库使用
    List的子类特点
    Exception in thread "main" java.util.ConcurrentModificationException解决方案
    Java中的集合Collection
    数组和集合的区别
    jsp 九大内置对象
    include指令与jsp:include动作标识的区别
    idea 2018注册码(激活码)
    内存的页面置换算法
    MYSQL的两种存储引擎区别
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12694232.html
Copyright © 2020-2023  润新知