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

 

posted @ 2021-07-14 19:40  PYWBKTDA  阅读(59)  评论(0编辑  收藏  举报