NOI模拟:棋赢

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/82802435

在这里插入图片描述

题解:
n n 很小,最后是一个跟sum有关的 j j 次多项式。

维护 s u m a sum^a 的和即可。 转移矩阵构造可以用拉格朗日插值法。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=55, mod=998244353;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (LL)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
inline int cinv(int a) {return power(a,mod-2);}

int n,m;
int s[N];

struct Combin {
	int fac[N],ifac[N];
	Combin() {
		fac[0]=1;
		for(int i=1;i<N;i++) fac[i]=mul(fac[i-1],i);
		ifac[N-1]=cinv(fac[N-1]);
		for(int i=N-2;~i;i--) ifac[i]=mul(ifac[i+1],i+1);
	} 
	inline int C(int a,int b) {return mul(fac[a],mul(ifac[b],ifac[a-b]));}
} C;

struct lgip {
	int num[N],yc[N],pre[N],suf[N],deg;	
	inline void init(int d) {
		deg=d+2;
		for(int i=1;i<=deg;i++) yc[i]=add(yc[i-1],power(i,d));
		for(int i=1;i<=deg;i++) {
			num[i]=1;
			for(int j=1;j<=deg;j++) if(j!=i) num[i]=mul(num[i],cinv(dec(i,j)));
		}
	}
	inline int getval(int d) {
		pre[0]=suf[deg+1]=1;
		for(int i=1;i<=deg;i++) pre[i]=mul(pre[i-1],dec(d,i));
		for(int i=deg;i>=1;i--) suf[i]=mul(suf[i+1],dec(d,i));
		int ans=0;
		for(int i=1;i<=deg;i++) ans=add(ans,mul(yc[i],mul(mul(pre[i-1],suf[i+1]),num[i])));
		return ans;
	}
} f[N];

typedef unsigned long long ULL;
const ULL LIM=ULLONG_MAX-(ULL)mod*mod;
struct matrix {
	ULL a[N][N];
	matrix(int t=0) {memset(a,0,sizeof(a)); for(int i=0;i<n;++i) a[i][i]=t;}
	friend inline matrix operator +(const matrix &a,const matrix &b) {
		matrix c(0);
		for(int i=0;i<n;i++) for(int j=0;j<n;j++) c.a[i][j]=add(a.a[i][j],b.a[i][j]);
		return c;
	}
	friend inline matrix operator *(const matrix &a,const matrix &b) {
		matrix c(0);
		for(int i=0;i<n;i++) 
			for(int k=0;k<n;k++)
				for(int j=0;j<n;j++) 
					((c.a[i][j]+=(ULL)a.a[i][k]*b.a[k][j])>=LIM) ? c.a[i][j]%=mod : 0;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				if(c.a[i][j]>=mod) c.a[i][j]%=mod;
		return c;
	}
	friend inline matrix operator ^(matrix a,int b) {
		matrix c(1);
		for(;b;b>>=1,a=a*a) if(b&1) c=c*a;
		return c;
	}
} A,tr;

int main() {
	n=rd(), m=rd();
	A.a[0][0]=1;
	for(int i=0;i<n;i++) f[i].init(i);
	for(int i=1;i<=m;i++) {
		int a=rd(), b=rd();
		static int val[N];
		for(int j=0;j<n;j++) val[j]=f[j].getval(b);
		for(int j=0;j<n;j++)
			for(int k=0;k<=j;k++) 
				tr.a[k][j]=mul(C.C(j,k),val[j-k]);
		A=A*(tr^a); 
	}
	s[0]=1;
	for(int i=1;i<=n-1;i++)
		for(int j=i;j>=0;j--) {
			s[j]=mul(s[j],mod-i);
			if(j) s[j]=add(s[j],s[j-1]);
		}
	for(int i=0;i<=n-1;i++) for(int j=1;j<=n-1;j++) s[i]=mul(s[i],cinv(j));
	int ans=0;
	for(int j=0;j<=n-1;j++) ans=add(ans,mul(A.a[0][j],s[j]));
	cout<<ans<<'\n';
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/82802435