BZOJ 3601 一個人的數論 (拉格朗日插值+莫比烏斯反演)

題意

題解

orz Freopen的博客

CODE

#pragma GCC optimize (3)
#include <bits/stdc++.h>
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
void read(int &res){
	char ch; for(;!isdigit(ch=getc()););
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
const int MAXD = 105;
const int MAXN = 1005;
const int mod = 1e9 + 7;
int d, n, p[MAXN], a[MAXN];

int inv[MAXD], invf[MAXD], rinv[MAXD];
int y[MAXD], cf[MAXD], dp[MAXD];

inline int qpow(int a, int b) {
	int re = 1;
	while(b) {
		if(b&1) re = 1ll * re * a % mod;
		a = 1ll * a * a % mod; b >>= 1;
	}
	return re;
}

int main () {
	read(d), read(n);
	for(int i = 1; i <= n; ++i) read(p[i]), read(a[i]);
	dp[0] = 1;
	for(int i = 1; i <= d+2; ++i) {
		y[i] = (y[i-1] + qpow(i, d)) % mod;
		for(int j = d+2; j >= 0; --j)
			dp[j] = ((j ? dp[j-1] : 0) - 1ll * dp[j] * i) % mod;
	}
	inv[0] = invf[0] = rinv[0] = 1;
	inv[1] = invf[1] = 1; rinv[1] = -1;
	for(int i = 2; i <= d+2; ++i)
		inv[i] = 1ll * (mod - mod/i) * inv[mod%i] % mod,
		invf[i] = 1ll * invf[i-1] * inv[i] % mod,
		rinv[i] = 1ll * rinv[i-1] * (-inv[i]) % mod;
	for(int i = 1; i <= d+2; ++i) {
		for(int j = 0; j <= d+2; ++j) {
			dp[j] = 1ll * ((j ? dp[j-1] : 0) - dp[j]) * inv[i] % mod;
			cf[j] = (cf[j] + 1ll * dp[j] * invf[i-1] % mod * rinv[d+2-i] % mod * y[i]) % mod;
		}
		for(int j = d+2; j >= 0; --j)
			dp[j] = ((j ? dp[j-1] : 0) - 1ll * dp[j] * i % mod) % mod;
	}
	int ans = 0;
	for(int i = 0; i <= d+1; ++i) {
		int tmp = 1;
		for(int j = 1; j <= n; ++j)
			tmp = 1ll * tmp * (qpow(qpow(p[j], a[j]), i) - 1ll * qpow(p[j], d) * qpow(qpow(p[j], a[j]-1), i) % mod) % mod;
		ans = (ans + 1ll * tmp * cf[i] % mod) % mod;
	}
	printf("%d\n", (ans + mod) % mod);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章