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

    P4091 [HEOI2016/TJOI2016]求和

    [f(n)=sum_{i=0}^{n}sum_{j=0}^{i}S_2(i,j)2^j(j!)\ =sum_{j=0}^{n}2^jj!sum_{i=0}^{n}S_2(i,j)\ =sum_{j=0}^{n}2^jj!sum_{i=0}^{n}dfrac{1}{j!}sum_{k=0}^{j}(-1)^{j-k}inom{j}{k}k^i\ =sum_{j=0}^{n}2^jsum_{i=0}^{n}sum_{k=0}^{j}(-1)^{j-k}inom{j}{k}k^i\ =sum_{j=0}^{n}2^jsum_{k=0}^{j}(-1)^{j-k}inom{j}{k}sum_{i=0}^{n}k^i\ =sum_{j=0}^{n}2^jsum_{k=0}^{j}(-1)^{j-k}inom{j}{k}dfrac{1-k^{n+1}}{1-k}\ =sum_{j=0}^{n}2^jj!sum_{k=0}^{j}dfrac{(-1)^{j-k}}{(j-k)!}dfrac{1-k^{n+1}}{(1-k)k!} ]

    水爆了,直接卷积就好了。等比数列记得判一下 (k=1) 就没有任何细节了。

    说一下为啥第二步把 (sumlimits_{i=j}^{n}) 换成 (sumlimits_{i=0}^{n}) 。正确性显然,加了一堆 (0)。 毕竟少一个变量比多一个变量方便吧。我一开始也是写从 (j) 开始的,最后一步发现没法卷积,审视了一下式子发现改掉边界就可以卷积了。所以其实我并不是一开始就这么算的,当然应该有人运气好或者直觉好一开始就这么写就可以少推几分钟。

    现在做出题都没有之前的兴奋感了,不知道是这题太水了还是我多项式做厌了。或许该停一阵子多项式?昨晚CF打炸了,根本没空开G这个数数题。其余部分感觉因为数数落下了,得去捡起来。

    const int N = 100005;
    const int M = N << 2;
    #define mod 998244353
    
    int n, A[M], B[M], ans;
    
    namespace math{
    int fac[N], ifc[N], inv[N];
    inline int qpow(int n, int k) {
    	int res = 1;
    	for (; k; k >>= 1, n = 1ll * n * n % mod)
    		if (k & 1) res = 1ll * n * res % mod;
    	return res;
    }
    void initmath(const int &n = N - 1) {
    	fac[0] = 1; rep(i, 1, n) fac[i] = 1ll * fac[i - 1] * i % mod;
    	ifc[n] = qpow(fac[n], mod - 2); per(i, n - 1, 0) ifc[i] = 1ll * ifc[i + 1] * (i + 1) % mod;
    	inv[1] =1; rep(i, 2, n) inv[i] = 1ll * inv[mod % i] * (mod - mod / i) % mod;
    }
    }
    using namespace math;
    
    namespace poly{
    int rev[M],lg,lim;
    void init_poly(const int &n) {
    	for (lg = 0, lim = 1; lim < n; ++lg, lim <<= 1);
    	for (int i = 0; i < lim; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
    }
    void NTT(int *a, int op) {
    	for (int i = 0; i < lim; ++i)
    		if (i > rev[i]) swap(a[i], a[rev[i]]);
    	const int g = op ? 3 : inv[3];
    	for (int i = 1; i < lim; i <<= 1) {
    		const int wn = qpow(g, (mod - 1) / (i << 1));
    		for (int j = 0; j < lim; j += i << 1) {
    			int w0 = 1;
    			for (int k = 0; k < i; ++k, w0 = 1ll * w0 * wn % mod) {
    				const int X = a[j + k], Y = 1ll * w0 * a[i + j + k] % mod;
    				a[j + k] = (X + Y) % mod, a[i + j + k] = (X - Y + mod) % mod;
    			}
    		}
    	}
    	if (op) return; const int ilim = qpow(lim, mod - 2);
    	for (int i = 0; i < lim; ++i) a[i] = 1ll * a[i] * ilim % mod;
    }
    #define clr(a, n) memset(a, 0, sizeof(int) * (n))
    #define cpy(a, b, n) memcpy(a, b, sizeof(int) * (n))
    void poly_mul(int *f, int *g, int *ans, int n, int m) {
    	static int A[M], B[M]; init_poly(n + m);
    	cpy(A, f, n), clr(A + n, lim - n), NTT(A, 1);
    	cpy(B, g, m), clr(B + m, lim - m), NTT(B, 1);
    	for (int i = 0; i < lim; ++i) ans[i] = 1ll * A[i] * B[i] % mod;
    	NTT(ans, 0);
    }
    }
    
    signed main(){
    	initmath();
    	n = read();
    	for (int i = 0; i <= n; ++i) A[i] = i & 1 ? mod - ifc[i] : ifc[i];
    	for (int i = 0; i <= n; ++i){
    		if (i == 1) B[i] = n + 1;
    		else B[i] = 1ll * (qpow(i, n + 1) - 1) * qpow(1ll * fac[i] * (i - 1) % mod, mod - 2) % mod;
    	}
    	poly::poly_mul(A, B, A, n + 1, n + 1);
    	for (int i = 0, j = 1; i <= n; ++i, j = j * 2 % mod) ans = (ans + 1ll * j * fac[i] % mod * A[i] % mod) % mod;
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    Android应用程序窗口(Activity)实现框架简要介绍和学习计划
    Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划
    《Android系统源代码情景分析》一书勘误
    Android应用程序窗口(Activity)的运行上下文环境(Context)的创建过程分析
    非IE内核浏览器支持activex插件
    让火狐浏览器可以访问含有activex控件网页的三种方式
    C++中delete和delete[]的区别
    动态加载JS脚本
    创建一个弹出DIV窗口
    C# 向下遍历删除子目录和子文件 及 向上遍历空的父目录
  • 原文地址:https://www.cnblogs.com/zzctommy/p/14282175.html
Copyright © 2011-2022 走看看