題目要求的是
設
(從貢獻角度)等價於
根據莫比烏斯反演,,得到
到這一步似乎無法做下去了,因爲 n 特別大。此時只能根據題解大膽猜測,數據這麼大還給的是質因子分解的形式,可能要用積性函數來做,因爲積性函數滿足 ,可以計算每一項質因子的貢獻最後乘起來得到答案。
觀察發現這個式子是一個接近卷積的形式,前兩個函數都是積性函數,根據經驗可以得知後面一個求和式是一個以 爲自變量的 次多項式,但這個多項式並不是一個積性函數。
注意到要將整個式子湊成一個積性函數,右邊那個和式必須是一個以 爲變量的積性函數,這樣整個式子可以湊成一個 Dirichlet 卷積,進一步根據題解大膽嘗試,將右邊 以多項式的形式傳入參數 代入得到:改變枚舉項,先枚舉 ,得到
這個時候右邊那部分就是積性函數了,並且由於 函數的特性,每一項 只有 1
和 pi
有貢獻,只要計算出這個多項式的所有係數 bi
就可以在規定時間內求解。
對於多項式求係數 bi
有兩種方法:拉格朗日插值多點插值,高斯消元
拉格朗日多點插值求解多項式係數還不會,且這裏 ,採用高斯消元進行求解
代碼:
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
const int maxn = 1e3 + 10;
int k,w;
int p[maxn],a[maxn],b[maxn];
int x[maxn][maxn],y[maxn];
inline int read() {
int x=0,f=1;char ch;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline int add(int x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
return x;
}
inline int sub(int x, int y) {
x -= y;
if (x < 0) {
x += mod;
}
return x;
}
inline int mul(int x, int y) {
return (long long) x * y % mod;
}
int fpow(int a,int b) {
int r = 1;
while (b) {
if (b & 1) r = mul(r,a);
a = mul(a,a);
b >>= 1;
}
return r;
}
void Gauss(int x[maxn][maxn],int y[maxn],int n) {
for (int i = 0; i <= n; i++) {
for (int j = 0; j < i; j++) {
int tp = mul(fpow(x[i][i],mod - 2),x[j][i]);
for (int k = 0; k <= n; k++) {
x[j][k] = sub(x[j][k],mul(tp,x[i][k]));
}
y[j] = sub(y[j],mul(tp,y[i]));
}
for (int j = i + 1; j <= n; j++) {
int tp = mul(fpow(x[i][i],mod - 2),x[j][i]);
for (int k = 0; k <= n; k++) {
x[j][k] = sub(x[j][k],mul(tp,x[i][k]));
}
y[j] = sub(y[j],mul(tp,y[i]));
}
}
}
int main() {
k = read(); w = read();
for (int i = 1; i <= w; i++)
p[i] = read(), a[i] = read();
y[0] = 0;
for (int i = 0; i <= k + 1; i++) {
for (int j = 0; j <= k + 1; j++)
x[i][j] = fpow(i,j);
if (i > 0) y[i] = add(y[i - 1],fpow(i,k));
}
Gauss(x,y,k + 1);
for (int i = 0; i <= k + 1; i++)
b[i] = mul(y[i],fpow(x[i][i],mod - 2));
int sum = 0, ans = 1;
for (int i = 0; i <= k + 1; i++) {
ans = 1;
for (int j = 1; j <= w; j++) {
int res = 0;
int t1 = fpow(p[j],a[j]), t2 = fpow(p[j],a[j] - 1);
res = add(res,fpow(t1,i));
res = sub(res,mul(fpow(t2,i),fpow(p[j],k)));
ans = mul(ans,res);
}
sum = add(sum,mul(b[i],ans));
}
printf("%d\n",sum);
return 0;
}