【题目链接】
【前置技能】
- k次幂前缀和
- 拉格朗日插值法
【题解】
- 题目大概要求的是若干 ∑i=1xik+1 ∑ i = 1 x i k + 1 的和,还要减去其中没出现的值。
- k k 次幂前缀和是个关于 x x 的次多项式,然后直接插值即可。
- 时间复杂度 O(TM3) O ( T M 3 ) 。
【代码】
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 60
#define mod 1000000007
using namespace std;
int Q, m, k, x[MAXN], y[MAXN];
LL n, len, a[MAXN], ans;
template <typename T> void chkmin(T &x, T y){x = min(x, y);}
template <typename T> void chkmax(T &x, T y){x = max(x, y);}
template <typename T> void read(T &x){
x = 0; int f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
LL qpow(LL a, int b){
a = a % mod;
LL ret = 1;
while (b){
if (b & 1) ret = ret * a % mod;
a = a * a % mod;
b >>= 1;
}
return ret;
}
LL calc(LL cur, int n){
LL ans = 0;
for (int i = 1; i <= n; ++i){
LL tmp = 1, tnp = 1;
for (int j = 1; j <= n; ++j){
if (i == j) continue;
tmp = tmp * (cur - x[j]) % mod;
tnp = tnp * (x[i] - x[j])% mod;
}
ans = (ans + y[i] * tmp % mod * qpow(tnp, mod - 2) % mod) % mod;
}
return ans;
}
int main(){
read(Q);
while (Q--){
read(n), read(m);
for (int i = 1; i <= m; ++i)
read(a[i]);
sort(a + 1, a + 1 + m);
a[0] = 0;
k = m + 1;
ans = 0;
y[0] = 0;
for (int i = 1; i <= k + 2; ++i)
x[i] = i, y[i] = (y[i - 1] + qpow(i, k)) % mod;
for (int i = 0; i <= m; ++i){
len = n - a[i];
ans = (ans + calc(len, k + 2)) % mod;
for (int j = i + 1; j <= m; ++j)
ans = (ans - qpow(a[j] - a[i], k)) % mod;
}
printf("%lld\n", (ans + mod) % mod);
}
return 0;
}