zoukankan      html  css  js  c++  java
  • P4091 [HEOI2016/TJOI2016]求和

    首先,我们需要知道第二类斯特林数组的组合意义(即容斥)

    (S^m_n = frac{1}{m!} sum_{k = 0}^{m}(-1)^k*C^k_m*(m - k)^n)

    然后,题目中让我们求

    (f(n) = sum_{i = 0}^nsum_{j = i}^nS^j_i*2^j*j!)

    我们直接将(S^j_i)展开成上述的组合意义,同时(j)(0)开始枚举(因为当(m > n)时,(S^m_n = 0)

    则有:

    (f(n) = sum_{i = 0}^nsum_{j = 0}^nfrac{1}{j!}sum_{k = 0}^j(-1)^k*C^k_j *(j - k)^i * 2^j*j!)

    我们发现(j!)可以约去,同时将(C^k_j)展开,(2^j)提到前边:

    (=sum_{i = 0}^nsum_{j = 0}^n2^jsum_{k = 0}^j(-1)^k * frac{j!}{k! * (j - k)!}*(j - k) ^ i)

    我们再讲(j!)提到前边,同时底数相同的化一下

    (=sum_{i= 0}^nsum_{j = 0}^n2^j * j!sum_{k= 0}^j frac{(-1)^k}{k!}frac{(j - k)^i}{(j - k)!})

    我们将第一个(sum)化到后面

    (sum_{j = 0}^n2^j*j!sum_{k=0}^jfrac{(-1)^k}{k!}frac{sum_{i = 0}^n(j - k)^i}{(j- k)!})

    根据等比数列求和公式

    (sum_{i = 0}^n(j - k)^i = frac{1 - (j - k)^{n + 1}}{1 - (j - k)})

    我们设

    (f(i) = frac{(-1)^i}{i!},g(i) = frac{1 - i^{n + 1}}{(1 - i)*i!})

    那么则有

    上式(=sum_{j = 0}^n2^jj!sum_{k = 0}^j f(k)g(j - k))

    发现,这是个卷积啊,直接上NTT就好了

    #include<cstdio>
    #include<iostream>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define LL long long
    using namespace std;
    const int N = 8e5 + 3;
    const LL mod = 998244353;
    LL n;
    LL a[N],b[N];
    LL fac[N];
    LL p[N];
    int r[N],l,limit = 1;
    inline LL quick(LL a,LL b){
    	LL res = 1;
    	while(b){
    		if(b & 1) res = res * a % mod;
    		b >>= 1;
    		a = a * a % mod;	
    	}
    	return res;
    }
    inline void nttle(LL *A,int type){
    	for(int i = 0;i < limit;++i) 
    		if(i < r[i]) swap(A[i],A[r[i]]);
    	for(int mid = 1;mid < limit;mid <<= 1){
    		LL Wn = (type == 1) ? quick(3,(mod - 1) / (mid << 1)) : 
    		quick(3,mod - 1 - (mod - 1) / (mid << 1));
    		for(int R = mid << 1,j = 0;j < limit;j += R){
    			LL w = 1;
    			for(int k = 0;k < mid;++k,w = w * Wn % mod){
    				LL x = A[j + k],y = w * A[j + mid + k] % mod;
    				A[j + k] = x + y;
    				A[j + mid + k] = x - y;
    				if(A[j + k] >= mod) A[j + k] -= mod;
    				if(A[j + mid + k] < 0) A[j + mid + k] += mod;
    			}
    		}
    	}
    	if(type == -1){
    		LL inv = quick(limit,mod - 2);
    		for(int i = 0;i < limit;++i) A[i] = A[i] * inv % mod;
    	}
    }
    int main(){
    	scanf("%lld",&n);
    	p[0] = fac[0] = 1;
    	for(LL i = 1;i <= n;++i){
    		p[i] = (p[i - 1] << 1) % mod;
    		fac[i] = fac[i - 1] * i % mod; 
    	}
    	for(LL i = 0;i <= n;++i){
    		if(i & 1) a[i] = (-1 + mod) * quick(fac[i],mod - 2) % mod;
    		else a[i] = 1 * quick(fac[i],mod - 2) % mod;
    		b[i] = (quick(i,n + 1) - 1 + mod) % mod * quick((i - 1 + mod) % mod * fac[i] % mod,mod - 2) % mod;
     	}
    	b[0] = 1,b[1] = n + 1;
     //	for(int i = 0;i <= n;++i) printf("%lld ",a[i]);puts("");
     //	for(int i = 0;i <= n;++i) printf("%lld ",b[i]);puts("");
     	while(limit < 2 * (n + 1)) limit <<= 1,++l;
     	for(int i = 0;i < limit;++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    	 //printf("%d ",r[i]);puts("");
     	nttle(a,1);nttle(b,1);
     	for(int i = 0;i < limit;++i) a[i] = a[i] * b[i] % mod;
     	nttle(a,-1);
     	LL ans = 0;
     //	for(int i = 0;i <= n;++i) printf("%lld ",a[i]);
     	for(int i = 0;i <= n;++i)
     		ans = (ans + p[i] * fac[i] % mod * a[i] % mod) % mod; 	
     	printf("%lld
    ",ans);
    	return 0;	
    }
    
  • 相关阅读:
    开源框架---通过Bazel编译使用tensorflow c++ API 记录
    图像处理---视频<->图片
    C++ ---释放内存(new和delete)
    目标检测---搬砖一个ALPR自动车牌识别的环境
    ubuntu系统---ubuntu16.04 + virtualenv + py2.7 + tf1.5.0 + keras2.2.4 + opencv2.4.9 +Numpy1.14
    Ubuntu系统---中英文问题小记
    Ubuntu系统---nvidia驱动下载之问题
    Ubuntu系统---又显示nvidia-smi 未找到命令
    Ubuntu系统---安装English版本之后的一些工作
    Ubuntu系统---安装“搜狗拼音法”导致桌面打不开
  • 原文地址:https://www.cnblogs.com/wyxdrqc/p/10627544.html
Copyright © 2011-2022 走看看