[Zijian47]梦中的项链
先不考虑环和相邻两项不同的限制,此时的问题即选择若干个数和为$w$,且选择$k$有$a_{k}$的系数,那么构造生成函数$G(x)=\sum_{i=1}^{n}a_{i}x^{i}$,则问题即求$\sum_{i\ge 0}G^{i}(x)=\frac{1}{1-G(x)}$
进一步的,要求相邻两项不同,构造$F(x)=\sum_{i=1}^{n}\sum_{j\ge 1}(-1)^{j-1}a_{i}x^{ij}$,求$\frac{1}{1-F(x)}$即可
关于正确性,考虑每一组方案的贡献,分类讨论:
1.若其中没有相邻两项相同,显然贡献为1
2.若其中有相邻两项相同,任取其中极长的一段,设长度为$l\ge 2$,那么将其划分为$j$段的贡献为$(-1)^{l-j}$(注意到每一段都会减少一个$-1$),而划分为$j$段的方案数为${l-1\choose j-1}$,因此贡献为$\sum_{j=1}^{l}(-1)^{l-j}{l-1\choose j-1}$,根据二项式定理将其展开,即为$(1+(-1))^{l-1}=0$
更进一步的,考虑环的限制,再乘上$H(x)=1+\sum_{i=1}^{n}\sum_{j\ge 2}(-1)^{j-1}(j-1)a_{i}x^{ij}$即可
正确性与之前类似,即将开头和末尾所构成的段也参与贡献
但这样还有两个小问题:
1.当所有位置都相同,若全长为$l$,此时的贡献即$(-1)^{l-1}$,那么即再减去$F(x)$即可
2.当全部为空,由于至少要两个,因此不允许出现,还要减去$1$
综上,答案即$\frac{H(x)}{1-F(x)}-F(x)-1$,计算复杂度为$o(n\log n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N (1<<18) 4 #define mod 998244353 5 struct poly{ 6 vector<int>a; 7 }A,B,C; 8 int n,a[N],rev[N]; 9 int qpow(int n,int m){ 10 int s=n,ans=1; 11 while (m){ 12 if (m&1)ans=1LL*ans*s%mod; 13 s=1LL*s*s%mod; 14 m>>=1; 15 } 16 return ans; 17 } 18 void ntt(poly &a,int n,int p){ 19 for(int i=0;i<(1<<n);i++) 20 if (i<rev[i])swap(a.a[i],a.a[rev[i]]); 21 for(int i=2;i<=(1<<n);i<<=1){ 22 int s=qpow(3,(mod-1)/i); 23 if (p)s=qpow(s,mod-2); 24 for(int j=0;j<(1<<n);j+=i) 25 for(int k=0,ss=1;k<(i>>1);k++,ss=1LL*ss*s%mod){ 26 int x=a.a[j+k],y=1LL*ss*a.a[j+k+(i>>1)]%mod; 27 a.a[j+k]=(x+y)%mod; 28 a.a[j+k+(i>>1)]=(x-y+mod)%mod; 29 } 30 } 31 if (p){ 32 int s=qpow((1<<n),mod-2); 33 for(int i=0;i<(1<<n);i++)a.a[i]=1LL*a.a[i]*s%mod; 34 } 35 } 36 poly mul(poly a,poly b,int n){ 37 while ((a.a.size()<(1<<n+1)))a.a.push_back(0); 38 while ((b.a.size()<(1<<n+1)))b.a.push_back(0); 39 for(int i=(1<<n);i<(1<<n+1);i++)a.a[i]=b.a[i]=0; 40 for(int i=0;i<(1<<n+1);i++)rev[i]=(rev[i>>1]>>1)+((i&1)<<n); 41 ntt(a,n+1,0); 42 ntt(b,n+1,0); 43 for(int i=0;i<(1<<n+1);i++)a.a[i]=1LL*a.a[i]*b.a[i]%mod; 44 ntt(a,n+1,1); 45 return a; 46 } 47 poly inv(poly a,int n){ 48 if (!n){ 49 poly ans; 50 ans.a.push_back(qpow(a.a[0],mod-2)); 51 return ans; 52 } 53 poly s=inv(a,n-1),ans=mul(s,a,n); 54 for(int i=0;i<(1<<n);i++)ans.a[i]=mod-ans.a[i]; 55 ans.a[0]+=2; 56 return mul(ans,s,n); 57 } 58 int main(){ 59 scanf("%d",&n); 60 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 61 for(int i=0;i<N;i++){ 62 A.a.push_back(0); 63 B.a.push_back(0); 64 } 65 for(int i=1;i<=n;i++) 66 for(int j=1;j<=n/i;j++){ 67 if (j&1)A.a[i*j]=(A.a[i*j]+a[i])%mod; 68 else A.a[i*j]=(A.a[i*j]-a[i]+mod)%mod; 69 if (j>=2){ 70 if (j&1)B.a[i*j]=(B.a[i*j]-1LL*(j-1)*a[i]%mod+mod)%mod; 71 else B.a[i*j]=(B.a[i*j]+1LL*(j-1)*a[i])%mod; 72 } 73 } 74 for(int i=0;i<N;i++){ 75 C.a.push_back(mod-A.a[i]); 76 B.a[i]=mod-B.a[i]; 77 } 78 C.a[0]++,B.a[0]++; 79 C=mul(inv(C,17),B,17); 80 for(int i=0;i<N;i++)C.a[i]=(C.a[i]-A.a[i]+mod)%mod; 81 C.a[0]--; 82 for(int i=0;i<=n;i++)printf("%d ",C.a[i]); 83 }