自嗨测试赛2

任意模数多项式乘法逆

多项式F与其乘法逆G相乘后,除常数项为1外,其他项系数都为0

由此列出式子,移项后就很明显能O(n^2)求出G1~Gn了

后面其实就是个矩阵加速数列递推了,特判完前n项后,直接矩阵快速幂就完了

Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;

const int maxk = 15;
int n, K, mod, f[maxk], g[maxk];

struct Mat {
	int a[maxk][maxk];
	Mat() { memset(a, 0, sizeof a); }
	void Init() {
		for(int i = 1;i <= K; ++i) a[i][i] = 1;
	}
	Mat operator * (const Mat &B) const {
		Mat ans;
		for(int i = 1;i <= K; ++i) {
			for(int j = 1;j <= K; ++j) {
				for(int k = 1;k <= K; ++k) {
					(ans.a[i][j] += (ll)a[i][k]*B.a[k][j]%mod)%=mod;
				}
			}
		}
		return ans;
	}
};

Mat fp(Mat a, int x) {
	Mat ans; ans.Init();
	for(;x > 0;x >>= 1, a = a*a)
		if(x&1) ans = ans*a;
	return ans;
}

int main() {
	freopen("poly.in","r",stdin);
	freopen("poly.out","w",stdout);
	scanf("%d%d%d", &n, &K, &mod);
	for(int i = 1;i <= K; ++i) scanf("%d", &f[i]);
	g[0] = 1;
	for(int i = 1;i <= K; ++i) {
		int now = 0;
		for(int j = 1;j <= i; ++j) (now -= (ll)f[j]*g[i-j]%mod)%=mod;
		g[i] = (now%mod+mod)%mod;
	}
	if(n <= K) return printf("%d
", g[n]), 0;
	Mat F, G;
	for(int i = 1;i <= K; ++i) G.a[i][1] = g[K-i+1];
	for(int i = 1;i <= K; ++i) F.a[1][i] = mod-f[i];
	for(int i = 2;i <= K; ++i) F.a[i][i-1] = 1;
	G = fp(F, n-K)*G;
	printf("%d
", G.a[1][1]);
	return 0;
}

明明的随机数

  • 先求出k1行k2列各行各列都不相同的情况,要用到n^2递推第一类斯特林数,斯特林反演

  • 然后乘以第二类斯特林数S2(n,k1)*S2(m,k2)就行了,这两个数可以O(klogn)求

对于第一步直接搬题解了

Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;

const int mod = 998244353;
int n, m, c, k1, k2;
int s1[3005][3005], fac[3005], fy[3005], f[3005], g[3005];

int fp(int a, int x, int ans = 1) {
	for(;x > 0;x >>= 1, a = (ll)a*a%mod) if(x&1) ans = (ll)ans*a%mod;
	return ans;
}

int C(int x, int y) {
	return (x<y||y<0) ? 0 : (ll)fac[x]*fy[y]%mod*fy[x-y]%mod;
}

void Init() {
	s1[0][0] = fac[0] = fy[0] = 1;
	for(int i = 1;i <= 3000; ++i) for(int j = 1;j <= i; ++j) s1[i][j] = (s1[i-1][j-1]+(ll)s1[i-1][j]*(i-1)%mod)%mod;
	for(int i = 1;i <= 3000; ++i) fac[i] = (ll)fac[i-1]*i%mod;
	fy[3000] = fp(fac[3000], mod-2);
	for(int i = 3000;i > 1; --i) fy[i-1] = (ll)fy[i]*i%mod;
}

int S2(int n, int m) {
	int S = 0;
	for(int i = 0;i <= m; ++i) {
		if(i&1) (S += mod-(ll)C(m, i)*fp(m-i, n)%mod)%=mod;
		else (S += (ll)C(m, i)*fp(m-i, n)%mod)%=mod;
	}
	return (ll)S*fy[m]%mod;
}

int main() {
	freopen("random.in","r",stdin);
	freopen("random.out","w",stdout);
	Init();
	int cs; scanf("%d", &cs);
	while(cs --> 0){
		scanf("%d%d%d%d%d", &n, &m, &k1, &k2, &c);
		if(c == 1) { printf("%d
", k1==1&&k2==1);continue; }
		if(k1 == k2 && k1 == 1) { printf("%d
", c%mod);continue; }
		for(int i = 1;i <= k1; ++i) {
			int now = 1, lst = fp(c, i);
			for(int j = 1;j <= k2; ++j) now = (ll)now*(lst-j+1)%mod;
			f[i] = (now%mod+mod)%mod;
			g[i] = 0;
			for(int j = 1;j <= i; ++j) {
				if((i-j)&1) (g[i] += mod-(ll)s1[i][j]*f[j]%mod)%=mod;
				else (g[i] += (ll)s1[i][j]*f[j]%mod)%=mod;
			}
		}
		printf("%lld
", (ll)g[k1]*S2(n, k1)%mod*S2(m, k2)%mod);
	}
	return 0;
}

凯爹博弈

又现学了点博弈论,SG函数,不过这道题先咕了

Code

原文地址:https://www.cnblogs.com/Lour688/p/14518320.html