zoukankan      html  css  js  c++  java
  • ARG102E:Stop. Otherwise...

    传送门

    Sol

    对于每个 (i) ,可以把 (k) 个数字分成 ((x,i-x)) 的若干组。
    那么就是求每组只能其中选择一个且可以重复的方案数。
    预处理 (f[i][j]) 表示从 (j) 个组内选 (i) 个,每个组必须选的方案数。
    (f[i][j]=(f[i-1][j]+f[i-1][j-1] imes 2)) 注意组有序,而选出来是无序的,所以要强制选择最后一组
    那么每个组可以不选的方案数 (g[i][j]) 就是

    [g[i][j]=sum_{t=0}^{j}(^{j}_{t})f[i][t] ]

    拆开组合数可以 (NTT) 优化。
    对于询问分两种情况

    1. (i) 为奇数
      那么 (x e i-x) 直接枚举多少个选组内的,其它的可重组合即可
    2. (i) 为偶数
      存在一组 (x=i-x) 枚举是否选 (x) (因为只能选一个),然后像奇数一样做即可
      (Theta(n^2logn)) 丝毫不虚
    # include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    namespace IO {
    	const int maxn((1 << 21) + 1);
    
    	char ibuf[maxn], *iS, *iT, c;
    	int f;
    
    	inline char Getc() {
    		return iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, maxn, stdin), iS == iT ? EOF : *iS++) : *iS++;
    	}
    
    	template <class Int> inline void In(Int &x) {
    		for (f = 1, c = Getc(); c < '0' || c > '9'; c = Getc()) f = c == '-' ? -1 : 1;
    		for (x = 0; c >= '0' && c <= '9'; c = Getc()) x = (x << 1) + (x << 3) + (c ^ 48);
    		x *= f;
    	}
    }
    
    using IO :: In;
    
    const int maxn(4005);
    const int mod(998244353);
    
    int f[maxn][maxn], c[maxn][maxn], fac[maxn], ifac[maxn];
    
    inline void Inc(int &x, int y) {
    	x += y;
    	if (x >= mod) x -= mod;
    }
    
    inline int Pow(ll x, int y) {
    	ll ret = 1;
    	for (; y; y >>= 1, x = x * x % mod)
    		if (y & 1) ret = ret * x % mod;
    	return ret;
    }
    
    inline int Calc(int n, int num, int res) {
    	int ret = 0;
    	if (!res) ret = f[n][num];
    	else {
    		for (int j = 0; j <= n; ++j)
    			Inc(ret, 1LL * f[n - j][num] * c[j + res - 1][j] % mod);
    	}
    	return ret;
    }
    
    int a[maxn << 2], b[maxn << 2], len, l, r[maxn << 2], w[2][maxn << 2];
    
    inline void NTT(int *p, int opt) {
    	for (int i = 0; i < len; ++i) if (i < r[i]) swap(p[i], p[r[i]]);
    	for (int i = 1; i < len; i <<= 1)
    		for (int j = 0, t = i << 1; j < len; j += t)
    			for (int k = 0; k < i; ++k) {
    				int nw = w[opt == -1 ? 1 : 0][len / i * k];
    				int x = p[j + k], y = 1LL * p[j + k + i] * nw % mod;
    				p[j + k] = (x + y) % mod, p[j + k + i] = (x - y + mod) % mod;
    			}
    	if (opt == -1) {
    		int inv = Pow(len, mod - 2);
    		for (int i = 0; i < len; ++i) p[i] = 1LL * p[i] * inv % mod;
    	}
    }
    
    inline void Init() {
    	f[0][0] = c[0][0] = ifac[0] = fac[0] = 1;
    	for (int i = 1, j; i <= 4000; ++i)
    		for (c[i][0] = j = 1; j <= i; ++j)
    			c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    	for (int i = 1; i <= 2000; ++i)
    		for (int j = 1; j <= 2000; ++j)
    			f[i][j] = (f[i - 1][j] + 1LL * f[i - 1][j - 1] * 2 % mod) % mod;
    	for (int i = 1; i <= 2000; ++i) fac[i] = 1LL * fac[i - 1] * i % mod;
    	ifac[2000] = Pow(fac[2000], mod - 2);
    	for (int i = 1999; i; --i) ifac[i] = 1LL * ifac[i + 1] * (i + 1) % mod;
    	for (len = 1; len <= 4000; len <<= 1) ++l;
    	for (int i = 0; i < len; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    	for (int i = 1; i < len; i <<= 1) {
    		int wn = Pow(3, (mod - 1) / (i << 1));
    		for (int nw = 1, k = 0; k < i; ++k, nw = 1LL * nw * wn % mod)
    			w[0][len / i * k] = nw, w[1][len / i * k] = Pow(nw, mod - 2);
    	}
    	for (int i = 0; i <= 2000; ++i) {
    		for (int j = 0; j < len; ++j) a[j] = b[j] = 0;
    		for (int j = 0; j <= 2000; ++j) a[j] = ifac[j], b[j] = 1LL * ifac[j] * f[i][j] % mod;
    		NTT(a, 1), NTT(b, 1);
    		for (int j = 0; j < len; ++j) a[j] = 1LL * a[j] * b[j] % mod;
    		NTT(a, -1);
    		for (int j = 0; j <= 2000; ++j) f[i][j] = 1LL * a[j] * fac[j] % mod;
    	}
    }
    
    int n, k;
    
    int main() {
    	In(k), In(n), Init();
    	int r = k << 1;
    	for (int i = 2; i <= r; ++i) {
    		if (i & 1) {
    			int num = max(0, min(i >> 1, i - 1) - max(1, i - k) + 1);
    			int res = k - (num << 1);
    			printf("%d
    ", Calc(n, num, res));
    		}
    		else {
    			int num = max(0, min(i >> 1, i - 1) - max(1, i - k) + 1);
    			int res = k - (num << 1) + 1;
    			if (num) --num;
    			printf("%d
    ", (Calc(n, num, res) + Calc(n - 1, num, res)) % mod);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    1. flask框架-简介/快速启动
    conda创建、查看、删除虚拟环境
    DOM用法(二)
    DOM用法(一)
    BOM用法
    Javascript对象
    JavaScript基础篇
    mysql 外连接
    mysql 连接表 内连接 inner
    mysql分组函数
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/10162723.html
Copyright © 2011-2022 走看看