ZR冬令营集训D4

T1 数数

回来补一下\(n\)天前的考试题.

很明显,我们通过枚举\(l\)\(r\),可以得到一个式子:

\(Ans = \sum_{i = r}^{n}(n - r)! * \sum_{j = 1}^{\lfloor { \frac{(i - 1)}{2}}\rfloor}P^{r -2}_{i - 2}\)

发现这个式子的值和\(l\)没任何关系,然后我们想办法化简一下

\(Ans = (n - r)!\sum_{i = r}^n*\lfloor\frac{(i - 1)}{2}\rfloor *\frac{(i - 2)!}{(i - r)!}\)

因为模数是\(998244353\),我们尽量向卷积上靠

设:

\(f(i) = \lfloor\frac{(i - 1)}{2}\rfloor * (i - 2)!\)

\(g(i) = \frac{1}{i!}\)

那么则有

\(Ans = (n - r)!\sum_{i = r}^nf(i)g(i - r)\)

发现貌似不能直接上卷积,我们只会套\(f(i)g(r - i)\)这样的

那我们就设

\(g'(i) = g(n - i)\)

那么有

\(Ans = (n - r)!\sum_{i = r}^nf(i)g'(n + r - i)\)

这样我们直接将\(g'\)\(f\)卷积,新的多项式的第\(n + i\)项就是\(r = i\)时的答案

时间复杂度\(O(nlog(n))\)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int N = 1e5 + 3;
const LL mod = 998244353;
LL a[N << 3],b[N << 3],g[N << 3];
int r[N << 3];
LL fac[N << 3],ans[N << 3];
int n,m,limit = 1,l,q;
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 = A[j + k + mid] * w % mod;
				A[j + k] = x + y;
				A[j + k + mid] = x - y;
				if(A[j + k] >= mod) A[j + k] -= mod;
				if(A[j + k + mid] < 0) A[j + k + mid] += mod;
			}
		}
	}
	if(type == -1){
		LL inv = quick(limit,mod - 2);
		for(int i = 0;i < limit;++i) A[i] = A[i] * inv % mod;
	}
}
inline int read(){
	int v = 0,c = 1;char ch = getchar();
	while(!isdigit(ch)){
		if(ch == '-') c = -1;
		ch = getchar();	
	}
	while(isdigit(ch)){
		v = v * 10 + ch - 48;
		ch = getchar(); 
	}	
	return v * c;
}	
int main(){
	n = read();q = read();
	fac[0] = 1;
	for(int i = 1;i <= n;++i) fac[i] = fac[i - 1] * i % mod;
	for(int i = 0;i <= n;++i){
		a[i] = (i >= 2) ? ((i - 1) / 2) * fac[i - 2] % mod : 0;
		b[i] = quick(fac[i],mod - 2);	
	} 
	reverse(b,b + n + 1);
	//for(int i = 1;i <= n;++i) g[i] = b[n - i + 1];

//	for(int i = 1;i <= n;++i) printf("%lld ",b[i]);puts("");
	while(limit < 2 * (n + 1)) limit <<= 1,++l;
//	cout << limit << endl; 
	for(int i = 0;i < limit;++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1)); 
	//for(int i = 0;i < limit;++i) printf("%d ",r[i]);puts("");
	nttle(a,1);
	nttle(b,1);//for(int i = 0;i < limit;++i) printf("%lld ",b[i]);puts("");
	for(int i = 0;i < limit;++i) a[i] = a[i] * b[i] % mod;
	nttle(a,-1);	
	for(int i = 2;i <= n;++i) ans[i] = fac[n - i] * a[n + i] % mod;
	while(q--){
		int x = read(),y = read();
		printf("%lld\n",ans[y]);
	}
	return 0;	
}
posted @ 2019-03-30 16:25  wyxdrqcccc  阅读(46)  评论(0编辑  收藏  举报