2020 省选模拟测试 Round #4 solution (20/02/03)

【比赛链接】http://59.61.75.5:8018/contest/214

A. Access

【题意】求执行最多 $k$ 次 $LCT$ 的 $access$ 能得到的树形态数。

【数据范围】$n leq 10^4.k leq 500$。

【题解】

考虑 $LCT$ 的性质,每个点最多只有一条重儿子边。

显然执行 $k$ 次操作后,会产生 $k$ 条不同的重链。

考虑树上背包。设 $f[u][x][0/1]$ 表示以 $u$ 为根的子树中有 $x$ 个点执行过一次操作, $u$ 是否执行过操作。直接转移即可。注意细节。

效率 $O(nk)$。期望得分:100。

【代码】

 1 #include<bits/stdc++.h>
 2 const int mod=998244353;
 3 long long f[10010][510][2],g[510][2];
 4 int siz[10010],n,k;
 5 std::vector<int> e[10010];
 6 inline void dfs ( int u,int fr )
 7 {
 8     siz[u]=1;f[u][0][0]=1;
 9     for ( int v:e[u] ) if ( v!=fr )
10     {
11         dfs(v,u);
12         for ( int x=0;x<=siz[u]+siz[v] and x<=k;x++ ) g[x][0]=g[x][1]=0;
13         for ( int x=0;x<=siz[u] and x<=k;x++ ) for ( int y=0;y<=siz[v] and x+y<=k;y++ )
14         {
15             (g[x+y+1][1]+=f[u][x][0]*f[v][y][0])%=mod;
16             (g[x+y+(y?1:0)][0]+=f[u][x][0]*f[v][y][0])%=mod;
17             (g[x+y+(y?1:0)][1]+=f[u][x][1]*f[v][y][0])%=mod;
18             (g[x+y][0]+=f[u][x][0]*f[v][y][1])%=mod;
19             (g[x+y][1]+=f[u][x][0]*f[v][y][1])%=mod;
20             (g[x+y][1]+=f[u][x][1]*f[v][y][1])%=mod;
21         }
22         for ( int x=0;x<=siz[u]+siz[v] and x<=k;x++ ) f[u][x][0]=g[x][0],f[u][x][1]=g[x][1];
23         siz[u]+=siz[v];
24     }
25     for ( int x=0;x<=siz[u] and x<=k;x++ ) g[x][0]=g[x][1]=0;
26     for ( int x=0;x<=siz[u] and x<=k;x++ ) for ( int y=0;y<2;y++ ) (g[x][y]+=f[u][x][y])%=mod;
27     for ( int x=0;x<=siz[u] and x<=k;x++ ) f[u][x][0]=g[x][0],f[u][x][1]=g[x][1];
28 }
29 signed main()
30 {
31     scanf("%d%d",&n,&k);
32     for ( int i=1,u,v;i<n;i++ ) scanf("%d%d",&u,&v),e[u].push_back(v),e[v].push_back(u);
33     dfs(1,0);long long ans=f[1][k][1];
34     for ( int x=0;x<k;x++ ) (ans+=f[1][x][0]+f[1][x][1])%=mod;
35     return !printf("%lld
",ans);
36 }
DTOJ4700

B. Convolution

【题意】求 $sumlimits_{i=1}^{n} sumlimits_{j=1}^{n} 2^{a_ia_j} mod 998244353$。

【数据范围】$n leq 10^5,a_i leq 10^5$。

【题解】

显然转化为统计 $a_i$ 的贡献。设权值为 $x$ 的数有 $b_x$ 个。记权值的最大值为 $m$。

考虑对式子进行转化,使式子化为 $sumlimits_{i=0}^{m} sumlimits_{j=0}^{m} f_i imes f_j imes g_{i+j}$ 的形式,以便 $NTT$ 优化。

则有:

$$egin{aligned} sumlimits_{i=0}^{m} sumlimits_{j=0}^{m} b_i imes b_j imes 2^{ij}  &= sumlimits_{i=0}^{m} sumlimits_{j=0}^{m} b_i imes b_j imes 2^{frac{1}{2}((i+j)^2-i^2-j^2)} \ &= sumlimits_{i=0}^{m} sumlimits_{j=0}^{m} frac{b_i}{sqrt{2}^{i^2}} imes frac{b_j}{sqrt{2}^{j^2}} imes sqrt{2}^{(i+j)^2}end{aligned}$$

直接 $NTT$ 优化即可。

效率 $O(m log m)(m=maxlimits_{1leq i leq n}{a_i})$。期望得分:100。

【代码】

 1 #include<bits/stdc++.h>
 2 const int mod=998244353,sqr2=116195171;
 3 const int G=3,invG=332748118;
 4 const int maxn=600000+10;
 5 int n,A[maxn],t,Pow[maxn],rev[maxn],ans;
 6 inline int power ( int x,long long y )
 7 {
 8     int z=1;
 9     for ( ;y;y>>=1,x=1LL*x*x%mod ) if ( y&1 ) z=1LL*z*x%mod;
10     return z;
11 }
12 inline void NTT ( int *a,int f )
13 {
14     for ( int i=0;i<t;i++ ) if ( i<rev[i] ) std::swap(a[i],a[rev[i]]);
15     for ( int i=2;i<=t;i<<=1 )
16     {
17         int wn=power((~f)?G:invG,(mod-1)/i);
18         for ( int j=0;j<t;j+=i )
19         {
20             int w=1;
21             for ( int k=0;k<i/2;k++,w=1LL*w*wn%mod )
22             {
23                 int x=a[j+k],y=1LL*w*a[j+k+i/2]%mod;
24                 a[j+k]=(x+y)%mod,a[j+k+i/2]=(x-y+mod)%mod;
25             }
26         }
27     }
28     if ( f==-1 )
29     {
30         int invt=power(t,mod-2);
31         for ( int i=0;i<t;i++ ) a[i]=1LL*a[i]*invt%mod;
32     }
33 }
34 signed main()
35 {
36     scanf("%d",&n);
37     for ( int x;n--; ) scanf("%d",&x),A[x]++;
38     for ( int i=0;i<=100000;i++ ) A[i]=1LL*A[i]*power(power(sqr2,1LL*i*i),mod-2)%mod;
39     for ( t=1;t<=200000;t<<=1 ) ;
40     for ( int i=0;i<t;i++ ) rev[i]=(rev[i>>1]>>1)|((i&1)?(t>>1):0);
41     NTT(A,1);
42     for ( int i=0;i<t;i++ ) A[i]=1LL*A[i]*A[i]%mod;
43     NTT(A,-1);
44     for ( int i=0;i<=200000;i++ ) ans=(ans+1LL*A[i]*power(sqr2,1LL*i*i))%mod;
45     return !printf("%d
",ans);
46 }
DTOJ4701

C. Gcd

【题意】求 $sumlimits_{i=1}^n sumlimits_{j=i}^{n} [j-i+1 leq n-2] imes maxlimits_{p,q in [1,i)cup (j,n],p eq q}gcd(a_p,a_q)$,多组数据。

【数据范围】$1 leq T leq 5, 1 leq n leq 2 imes 10^{5}, 1 leq a_{i} leq 2 imes 10^{5}$。

【题解】

考虑枚举 $gcd$。显然只有 $gcd$ 的倍数会对答案造成影响。

假设 $gcd$ 倍数的位置分别为 $a_i(1 leq i leq p)$,则显然答案一定包含以下三种情况之一:

① $(a_1,a_2)$ ② $(a_1,a_n)$ ③ $(a_{n-1},a_n)$

查询三次即可。用线段树维护每个点为左端点的时候最远删到了哪,以及还剩多少个区间没有被删即可。

效率 $O(m ln m + mlog n)(m=maxlimits_{1 leq i leq n} a_i)$。期望得分:100。

【代码】

  1 #include<bits/stdc++.h>
  2 inline int read ( void )
  3 {
  4     int x=0;char ch;
  5     while ( !isdigit(ch=getchar()) ) ;
  6     for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
  7     return x;
  8 }
  9 const int maxn=200000+10;
 10 int n,m=200000,a[maxn],pos[maxn];
 11 struct tree { long long sum;int min,max,num; } t[maxn<<2];
 12 #define ls (k<<1)
 13 #define rs (k<<1|1)
 14 #define mid ((l+r)>>1)
 15 inline void pushup ( int k )
 16 {
 17     int g[4]={t[ls].min,t[rs].min,t[ls].max,t[rs].max};
 18     std::sort(g,g+4);t[k].min=g[0];t[k].num=0;
 19     if ( t[k].min==t[ls].min ) t[k].num+=t[ls].num;
 20     if ( t[k].min==t[rs].min ) t[k].num+=t[rs].num;
 21     for ( int i=1;i<4;i++ ) if ( g[i]!=g[0] ) { t[k].max=g[i];break; }
 22     t[k].sum=t[ls].sum+t[rs].sum;
 23 }
 24 inline void build ( int k,int l,int r )
 25 {
 26     t[k].sum=0;
 27     if ( l==r ) { t[k].sum=l;t[k].min=l;t[k].max=n+2;t[k].num=1;return; }
 28     build(ls,l,mid);build(rs,mid+1,r);pushup(k);
 29 }
 30 inline void pushdown ( int k )
 31 {
 32     int p=t[k].min;
 33     if ( t[ls].min<p ) t[ls].sum+=1LL*(p-t[ls].min)*t[ls].num,t[ls].min=p;
 34     if ( t[rs].min<p ) t[rs].sum+=1LL*(p-t[rs].min)*t[rs].num,t[rs].min=p;
 35 }
 36 inline long long query ( int k,int l,int r,int ql,int qr )
 37 {
 38     if ( ql<=l and r<=qr ) return t[k].sum;
 39     pushdown(k);
 40     if ( qr<=mid ) return query(ls,l,mid,ql,qr);
 41     if ( ql>mid ) return query(rs,mid+1,r,ql,qr);
 42     return query(ls,l,mid,ql,qr)+query(rs,mid+1,r,ql,qr);
 43 }
 44 inline void update ( int k,int l,int r,int ql,int qr,int p )
 45 {
 46     if ( ql<=l and r<=qr )
 47     {
 48         if ( t[k].min>=p ) return;
 49         if ( t[k].max>p or l==r ) { t[k].sum+=1LL*(p-t[k].min)*t[k].num,t[k].min=p;return; }
 50     }
 51     pushdown(k);
 52     if ( ql<=mid ) update(ls,l,mid,ql,qr,p);
 53     if ( qr>mid ) update(rs,mid+1,r,ql,qr,p);
 54     pushup(k);
 55 }
 56 inline int find ( int k,int l,int r,int p )
 57 {
 58     if ( l==r ) return (t[k].min>p)?l:(n+1);
 59     pushdown(k);
 60     if ( t[rs].min>p ) return std::min(find(ls,l,mid,p),mid+1);
 61     else return find(rs,mid+1,r,p);
 62 }
 63 #undef ls
 64 #undef rs
 65 #undef mid
 66 inline long long solve ( int l,int r )
 67 {
 68     if ( l>r ) return 0;
 69     int p=std::max(find(1,1,n,r),l);
 70     long long res=(p>l)?query(1,1,n,l,p-1):0;
 71     update(1,1,n,l,r,r+1);
 72     return 1LL*(p-l)*(r+1)-res;
 73 }
 74 signed main()
 75 {
 76     for ( int T=read();T--; )
 77     {
 78         n=read();build(1,1,n);m=0;
 79         for ( int i=1;i<=n;i++ ) m=std::max(m,a[i]=read());
 80         for ( int i=1;i<=m;i++ ) pos[i]=0;
 81         for ( int i=1;i<=n;i++ ) pos[a[i]]=i;
 82         long long ans=0;
 83         for ( int i=m;i;i-- )
 84         {
 85             std::vector<int> G;
 86             int min1=n+1,min2=n+1,max1=0,max2=0;
 87             for ( int j=i;j<=m;j+=i ) if ( pos[j] ) G.push_back(pos[j]);
 88             for ( int x:G )
 89             {
 90                 if ( x>max1 ) max2=max1,max1=x;
 91                 else if ( x>max2 ) max2=x;
 92                 if ( x<min1 ) min2=min1,min1=x;
 93                 else if ( x<min2 ) min2=x;
 94             }
 95             ans=ans+i*(solve(min1+1,max1-1)+solve(min2+1,n)+solve(1,max2-1));
 96         }
 97         printf("%lld
",ans);
 98     }
 99     return 0;
100 }
DTOJ4702
原文地址:https://www.cnblogs.com/RenSheYu/p/12257500.html