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\n",ans); 36 }
B. Convolution
【题意】求 $\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} 2^{a_ia_j} \mod 998244353$。
【数据范围】$n \leq 10^5,a_i \leq 10^5$。
【题解】
显然转化为统计 $a_i$ 的贡献。设权值为 $x$ 的数有 $b_x$ 个。记权值的最大值为 $m$。
考虑对式子进行转化,使式子化为 $\sum\limits_{i=0}^{m} \sum\limits_{j=0}^{m} f_i\times f_j \times g_{i+j}$ 的形式,以便 $NTT$ 优化。
则有:
$$\begin{aligned} \sum\limits_{i=0}^{m} \sum\limits_{j=0}^{m} b_i \times b_j \times 2^{ij} &= \sum\limits_{i=0}^{m} \sum\limits_{j=0}^{m} b_i \times b_j \times 2^{\frac{1}{2}((i+j)^2-i^2-j^2)} \\ &= \sum\limits_{i=0}^{m} \sum\limits_{j=0}^{m} \frac{b_i}{\sqrt{2}^{i^2}} \times \frac{b_j}{\sqrt{2}^{j^2}} \times \sqrt{2}^{(i+j)^2}\end{aligned}$$
直接 $NTT$ 优化即可。
效率 $O(m \log m)(m=\max\limits_{1\leq 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\n",ans); 46 }
C. Gcd
【题意】求 $\sum\limits_{i=1}^n \sum\limits_{j=i}^{n} [j-i+1 \leq n-2] \times \max\limits_{p,q \in [1,i)\cup (j,n],p \neq q}\gcd(a_p,a_q)$,多组数据。
【数据范围】$1 \leq T \leq 5, 1 \leq n \leq 2 \times 10^{5}, 1 \leq a_{i} \leq 2 \times 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 + m\log n)(m=\max\limits_{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\n",ans); 98 } 99 return 0; 100 }