码迷,mamicode.com
首页 > 其他好文 > 详细

Gnutella Chessmaster

时间:2020-01-08 23:01:05      阅读:112      评论:0      收藏:0      [点我收藏+]

标签:ble   type   swa   unsigned   --   n+1   signed   floor   黑白   

题目
这是一个不需要推式子的清真做法。
首先我们把棋盘黑白染色,得到两个新的棋盘,然后分别在两个棋盘上算方案数\(r,R\)再卷起来就好了。
观察可得棋盘\(B_1=(1,1,3,3,\cdots),B_2=(2,2,4,4,\cdots)\),行数分别为\(n,n-1\)
对于\(B_1\)运用Goldman-Joichi-White定理得到\(\sum\limits_{i=0}^nr_ix^{\underline{n-i}}=x^{\lfloor\frac n2\rfloor}(x+1)^{\lceil\frac n2\rceil}\)
对于\(B_2\)运用Goldman-Joichi-White定理得到\(\sum\limits_{i=0}^{n-1}R_ix^{\underline{n-i}}=(x+2)^{\lfloor\frac n2\rfloor}(x+1)^{\lceil\frac n2\rceil-1}\)
如果我们直接普通多项式转下降幂多项式就可以得到一个\(O(n\log^2n)\)的辣鸡作法。
我们观察普通多项式转下降幂多项式的过程:多点求值,IFDT。
其中IFDT就是先变EGF再卷一个\(e^{-x}\),复杂度为\(O(n\log n)\),常数也很优秀。
而我们显然不需要多点求值,右边这个明摆着就能\(O(n\log n)\)快速多点求值,常数比上面的IFDT更加优秀。
这样我们就可以得到两个下降幂多项式了,reverse一下就可以得到\(r,R\),再卷起来就好了。

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
using std::reverse;
using u64=unsigned long long;
const int N=262150,P=998244353;
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put(' ');}
}using namespace IO;
void swap(int&x,int&y){x^=y^=x^=y;}
int mod(int x){return x+(x>>31&P);}
int mul(int a,int b){return (u64)a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int w[N],ifac[N],r[N],lim;
void init(int n)
{
    int l=33-__builtin_clz(n),g(pow(3,(P-1)>>l));
    lim=1<<l,ifac[0]=w[lim>>1]=1,--l;
    for(int i=1;i<lim;++i) r[i]=(r[i>>1]>>1)|((i&1)<<l);
    for(int i=1;i<=n;++i) ifac[i]=mul(ifac[i-1],pow(i,P-2));
    for(int i=(lim>>1)+1;i<lim;++i) w[i]=mul(w[i-1],g);
    for(int i=(lim>>1)-1;i;--i) w[i]=w[i<<1];
    return ;
}
void NTT(int*a,int f)
{
    if(!~f) reverse(a+1,a+lim);
    static u64 t[N];
    for(int i=0;i<lim;++i) t[r[i]]=a[i];
    for(int i=1;i<lim;i<<=1) for(int j=0,d=i<<1;j<lim;j+=d) for(int k=0,x;k<i;++k) x=t[i|j|k]*w[i|k]%P,t[i|j|k]=t[j|k]+P-x,t[j+k]+=x;
    for(int i=0;i<lim;++i) a[i]=t[i]%P;
    if(!~f) for(int i=0,p=(P-(P-1)/lim);i<lim;++i) a[i]=mul(a[i],p);
}
int e[N],f[N],g[N];
int main()
{
    int n=read();
    if(n==1) return !printf("1");
    init(n);
    for(int i=0;i<=n;++i) e[i]=i&1? P-ifac[i]:ifac[i];
    for(int i=1;i<=n;++i) f[i]=mul(mul(pow(i,n>>1),pow(i+1,(n+1)/2)),ifac[i]);
    for(int i=0;i<n;++i) g[i]=mul(mul(pow(i+2,n>>1),pow(i+1,(n-1)/2)),ifac[i]);
    NTT(e,1),NTT(f,1),NTT(g,1);
    for(int i=0;i<lim;++i) f[i]=mul(f[i],e[i]),g[i]=mul(g[i],e[i]);
    NTT(f,-1),NTT(g,-1),memset(f+n+1,0,(lim-n-1)<<2),memset(g+n,0,(lim-n)<<2),reverse(f,f+n+1),reverse(g,g+n),NTT(f,1),NTT(g,1);
    for(int i=0;i<lim;++i) f[i]=mul(f[i],g[i]);
    NTT(f,-1);
    for(int i=1;i<n*2;++i) printf("%d ",f[i]);
}

段落引用

Gnutella Chessmaster

标签:ble   type   swa   unsigned   --   n+1   signed   floor   黑白   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12169039.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!