• [Zijian47]梦中的项链


    先不考虑环和相邻两项不同的限制,此时的问题即选择若干个数和为$w$,且选择$k$有$a_{k}$的系数,那么构造生成函数$G(x)=sum_{i=1}^{n}a_{i}x^{i}$,则问题即求$sum_{ige 0}G^{i}(x)=frac{1}{1-G(x)}$

    进一步的,要求相邻两项不同,构造$F(x)=sum_{i=1}^{n}sum_{jge 1}(-1)^{j-1}a_{i}x^{ij}$,求$frac{1}{1-F(x)}$即可

    关于正确性,考虑每一组方案的贡献,分类讨论:

    1.若其中没有相邻两项相同,显然贡献为1

    2.若其中有相邻两项相同,任取其中极长的一段,设长度为$lge 2$,那么将其划分为$j$段的贡献为$(-1)^{l-j}$(注意到每一段都会减少一个$-1$),而划分为$j$段的方案数为${l-1choose j-1}$,因此贡献为$sum_{j=1}^{l}(-1)^{l-j}{l-1choose j-1}$,根据二项式定理将其展开,即为$(1+(-1))^{l-1}=0$

    更进一步的,考虑环的限制,再乘上$H(x)=1+sum_{i=1}^{n}sum_{jge 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(nlog 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
  • 相关阅读:
    中序遍历【递归算法】和【非递归算法】
    等价无穷小替换
    轮转访问MAC协议
    曲率
    Java I/O流 01
    Java 集合框架 04
    Java 集合框架 03
    Java 集合框架 02
    Java 集合框架 01
    Java 常见对象 05
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15012641.html
Copyright © 2020-2023  润新知