zoukankan      html  css  js  c++  java
  • bzoj4555:[Tjoi2016&Heoi2016]求和

    传送门

    首先我们需要知道第二类斯特林数的通项公式

    [S(n,m)=frac{1}{m!}sum_{k=0}^{m}(-1)^kinom{m}{k}(m-k)^n ]

    然后我们就可以将题目给的式子里的第二类斯特林数拆开

    [f(n)=sum_{i=0}^{n}sum_{j=0}^{i}frac{1}{j!}sum_{k=0}^{j}(-1)^kinom{j}{k}(j-k)^i2^j(j!)\ f(n)=sum_{i=0}^{n}sum_{j=0}^{i}2^jsum_{k=0}^{j}(-1)^kinom{j}{k}(j-k)^i\ ]

    然后发现这个式子貌似做不下去了,然后考虑对于(j>i)(S(i,j))都是没有意义的

    [f(n)=sum_{i=0}^{n}sum_{j=0}^{n}2^jsum_{k=0}^{j}(-1)^kinom{j}{k}(j-k)^i\ ]

    然后把组合数拆开

    [f(n)=sum_{i=0}^{n}sum_{j=0}^{n}2^jsum_{k=0}^{j}(-1)^kfrac{j!}{k!(j-k)!}(j-k)^i\ ]

    然后调换一下(sum)

    [f(n)=sum_{j=0}^{n}2^jj!sum_{k=0}^{j}frac{(-1)^k}{k!}frac{sum_{i=0}^{n}(j-k)^i}{(j-k)!}\ ]

    [f(i)=frac{(-1)^i}{i!}\ g(i)=frac{sum_{j=0}^{n}i^j}{i!} ]

    那么

    [f(n)=sum_{j=0}^{n}2^jj!sum_{k=0}^{j}f(k)g(j-k) ]

    可以发现后面是一个卷积的形式,可以用ntt快速计算,然后这个题就做完了

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<cmath>
    using namespace std;
    void read(int &x){
    	char ch;bool ok;
    	for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
    	for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    #define rg register
    const int maxn=4e5+10,mod=998244353,g=3,gi=332748118;
    int n,a[maxn],b[maxn],m,fac[maxn],inv[maxn],len,ans,r[maxn];
    int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
    int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    int del(int x,int y){return x-y<0?x-y+mod:x-y;}
    int mi(int a,int b){
    	int ans=1;
    	while(b){
    		if(b&1)ans=mul(ans,a);
    		b>>=1,a=mul(a,a);
    	}
    	return ans;
    }
    void ntt(int *a,int f){
    	for(rg int i=0;i<n;i++)if(r[i]>i)swap(a[i],a[r[i]]);
    	for(rg int i=1;i<n;i<<=1){
    		int wn=mi(f?g:gi,(mod-1)/(i<<1));
    		for(rg int j=0;j<n;j+=i<<1){
    			int w=1;
    			for(rg int k=0;k<i;k++){
    				int x=a[j+k],y=mul(w,a[i+j+k]);
    				a[j+k]=add(x,y),a[j+k+i]=del(x,y),w=mul(w,wn);
    			}
    		}
    	}
    	if(f)return ;int inv=mi(n,mod-2);
    	for(rg int i=0;i<n;i++)a[i]=mul(a[i],inv);
    }
    int sum(int q){return q==1?n+1:mul(del(mi(q,n+1),1),mi(del(q,1),mod-2));}
    int main(){
    	read(n);fac[0]=1;
    	for(rg int i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
    	inv[n]=mi(fac[n],mod-2);
    	for(rg int i=n-1;i>=0;i--)inv[i]=mul(inv[i+1],i+1);
    	for(rg int i=0;i<=n;i++)a[i]=mul((i&1?mod-1:1),inv[i]);
    	for(rg int i=0;i<=n;i++)b[i]=mul(sum(i),inv[i]);
    	m=n+n;for(n=1;n<=m;n<<=1)len++;m=m/2;
    	for(rg int i=0;i<=n;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
        ntt(a,1),ntt(b,1);
    	for(rg int i=0;i<=n;i++)a[i]=mul(a[i],b[i]);
    	ntt(a,0);
    	for(rg int i=0;i<=m;i++)ans=add(ans,mul(mi(2,i),mul(fac[i],a[i])));
    	printf("%d
    ",ans);
    }
    
    
  • 相关阅读:
    alg--动态规划(dynamic planning)
    alg--分治法
    汇编-理解call,ret
    汇编--实验7
    leetCode笔记--binary tree
    leetCode笔记--(1)
    C#获取当前路径的方法如下
    VS2013 快捷键 与 RESHARPER 冲突
    使用Visual Studio 2013进行单元测试--初级篇
    VS 插件
  • 原文地址:https://www.cnblogs.com/lcxer/p/10761615.html
Copyright © 2011-2022 走看看