计算烷烃的同分异构体个数

今天做__debug的题就有这道,他的Blog也写得挺清楚。

相当于计算度数不超过4的无标号无根树个数。按照无根树的套路,我们直接枚举子树即可。
但是无根树可以用exp来搞,这个度数有限制。
我们可以换一种方法,显然子树每个点度数不超过3,记其生成函数为 A ,可以用Polya定义来计数:
首先假设儿子彼此有序,然后规定如果某个置换之后得到两个等价的东西,那么这两个算一个方案。 我们枚举每一个置换,利用Burnside引理,容易得到:

A = 1 + x 2 A ( x 3 ) + 3 A ( x 2 ) A ( x ) + A ( x ) 3 6

相当于每种置换的每个循环节内部必须严格相等。 枚举环然后系数就是这样的置换的个数,利用分治FFT在 O ( n log 2 n ) 时间内预处理。

然后用经典的枚举重心的儿子的方法,就可以在 O ( n log n ) 的时间内解决单组询问。

考虑如何解决多组询问,我们发现,对于任意一棵无根树,我们记其点的等价类为 p 个,边的等价类有 q 个,对称边(两边的点等价)有 s 个,那么有 s 1 ,且 p q + s = 1

证明如下:
如果有对称边,那么显然 p q = 0 p q + s = 1
否则等价点不会为重心,重心等价类只有1个点,重心一定在其路径上,他们的父亲是等价边。 我们可以得到 p q = 1 (加上重心)。

然后求出 p , q , s 即可。

p 相当于有根树计数,是4个儿子拼起来,同理用Polya可得:

P ( x ) = x 6 A ( x 4 ) + 6 A ( x 2 ) A 2 ( x ) + 3 A 2 ( x 2 ) + 8 A ( x 3 ) A ( x ) + A ( x 4 ) 24

q 相当于拼接两棵子树:
Q ( x ) = ( A ( x ) 1 ) 2 + ( A ( x 2 ) 1 ) 2

s 相当于拼接两棵相同子树:
S ( x ) = A ( x 2 )

然后就做完了。

不过求 A 时候分治FFT要稍微修改一下,因为 A [ 0 , m i d ] A [ m i d + 1 , r ] 的贡献要用到 [ m i d + 1 , r ] ,这个我们特判一下 l 就行了,然后没计算到的贡献在下面分治的时候额外加上即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int RLEN=1<<18|1;
inline char nc() {
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
    char ch=nc(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
    return i*f;
}
inline void W(int x) {
    static int buf[50];
    if(!x) {putchar('0'); return;}
    if(x<0) {putchar('-'); x=-x;}
    while(x) {buf[++buf[0]]=x%10; x/=10;}
    while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}

const int mod=998244353, G=3;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (LL)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}

const int N=1<<20|1;
const int inv6=power(6,mod-2), inv2=(mod+1)/2, inv24=mul(inv2,mul(inv2,inv6)); 
int n,k,w[N],pos[N],A[N],B[N],tp[N],tp2[N],tp3[N];
inline void init(int nn) {
    for(k=1;k<=nn;k<<=1);
    for(int i=1;i<k;i++) pos[i]=(i&1) ? ((pos[i>>1]>>1)^(k>>1)) : (pos[i>>1]>>1);
}
inline void dft(int *a,int o=1) {
    for(int i=1;i<k;i++) if(pos[i]>i) swap(a[pos[i]],a[i]);
    for(int bl=1;bl<k;bl<<=1) {
        int tl=bl<<1, wn=power(G,(mod-1)/tl);
        w[0]=1; for(int i=1;i<bl;i++) w[i]=mul(w[i-1],wn);
        for(int bg=0;bg<k;bg+=tl)
            for(int j=0;j<bl;j++) {
                int &t1=a[bg+j], &t2=a[bg+j+bl], t=mul(t2,w[j]);
                t2=dec(t1,t); t1=add(t1,t);
            }
    }
    if(!~o) {
        const int inv=power(k,mod-2); reverse(a+1,a+k);
        for(int i=0;i<k;i++) a[i]=mul(a[i],inv);
    }
}
inline void solve(int l,int r) {
    if(l==r) {
        if(!l) A[l]=1;
        else A[l]=add(A[l],((l%3==1) ? mul(2,A[l/3]) : 0)), A[l]=mul(A[l],inv6);
        return;
    } 
    int mid=(l+r)>>1, len=r-l;
    solve(l,mid); init(len*2+mid-l);
    memset(tp,0,sizeof(int)*k); 
    memset(tp2,0,sizeof(int)*k);
    memset(tp3,0,sizeof(int)*k);
    memcpy(tp,A+l,sizeof(int)*(mid-l+1));
    memcpy(tp2,A,sizeof(int)*len);
    for(int i=0,j;(j=i*2)<=len;i++) tp3[j]=A[i];

    dft(tp); dft(tp2); dft(tp3);
    for(int i=0;i<k;i++) tp2[i]=mul(tp2[i],mul(tp2[i],tp[i]));
    dft(tp2,-1);
    if(!l) {
        for(int i=mid+1;i<=r;i++) A[i]=add(A[i],tp2[i-l-1]);
    } else {
        for(int i=mid+1;i<=r;i++) A[i]=add(A[i],mul(tp2[i-l-1],3));
    } 
    for(int i=0;i<k;i++) tp[i]=mul(tp[i],tp3[i]);
    dft(tp,-1);
    for(int i=mid+1;i<=r;i++) A[i]=add(A[i],mul(tp[i-l-1],3));
    solve(mid+1,r);
}
const int L=1e5;
int main() {
    solve(0,n=L); init(L*4);
    memset(tp,0,sizeof(int)*k);
    memset(tp2,0,sizeof(int)*k);
    memset(tp3,0,sizeof(int)*k);
    for(int i=0;i<=n;i++) tp[i]=A[i];
    for(int i=0;i*2<=n;i++) tp2[i*2]=A[i];
    for(int i=0;i*3<=n;i++) tp3[i*3]=A[i];
    dft(tp); dft(tp2); dft(tp3);
    for(int i=0;i<k;i++) {
        int s=0;
        s=add(s,power(tp[i],4));
        s=add(s,mul(6,mul(tp2[i],power(tp[i],2))));
        s=add(s,mul(3,power(tp2[i],2)));
        s=add(s,mul(8,mul(tp3[i],tp[i])));
        tp[i]=s;
    } dft(tp,-1);
    for(int i=0;i<=n;i++) 
        B[i]=add(tp[i],(!(i%4)) ? mul(6,A[i/4]) : 0), B[i]=mul(B[i],inv24);
    for(int i=n;i;i--) B[i]=B[i-1]; B[0]=0;
    for(int i=0;i<=n;i+=2) B[i]=add(B[i],A[i/2]);
    memset(tp,0,sizeof(int)*k);
    for(int i=1;i<=n;i++) tp[i]=A[i];
    dft(tp); 
    for(int i=0;i<k;i++) tp[i]=mul(tp[i],tp[i]);
    dft(tp,-1);
    for(int i=1;i<=n;i++) B[i]=dec(B[i],mul(tp[i],inv2));
    for(int i=2;i<=n;i+=2) B[i]=dec(B[i],mul(A[i/2],inv2));
    for(int T=rd();T;T--)
        W(B[rd()]), putchar('\n');
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/80961408