点击打开链接
第十六届北京师范大学程序设计竞赛决赛
B - 外挂使用拒绝
思路:
设dp[k][i]dp[k][i]为:操作kk天后第ii个账号还有的钱的数量, 那么有以下等式:
⎧⎩⎨⎪⎪⎪⎪⎪⎪dp[k][1]=dp[k−1][1]dp[k][2]=dp[k−1][2]+dp[k][1]......dp[k][n]=dp[k][n−1]+dp[k−1][n]{dp[k][1]=dp[k−1][1]dp[k][2]=dp[k−1][2]+dp[k][1]......dp[k][n]=dp[k][n−1]+dp[k−1][n] ⇒ ⇒ ⎧⎩⎨⎪⎪⎪⎪⎪⎪dp[k−1][1]=dp[k][1]dp[k−1][2]=dp[k][2]−dp[k][1]......dp[k−1][n]=dp[k][n]−dp[k][n−1] {dp[k−1][1]=dp[k][1]dp[k−1][2]=dp[k][2]−dp[k][1]......dp[k−1][n]=dp[k][n]−dp[k][n−1]
即:
⎡⎣⎢⎢⎢⎢⎢⎢dp[k−1][1]dp[k−1][2]dp[k−1][3]....dp[k−1][n]⎤⎦⎥⎥⎥⎥⎥⎥[dp[k−1][1]dp[k−1][2]dp[k−1][3]....dp[k−1][n]] = ⎡⎣⎢⎢⎢⎢⎢⎢1−10...001−1...0001...0...............000...−1000...1⎤⎦⎥⎥⎥⎥⎥⎥[100...00−110...000−11...00..................000...−11]⎡⎣⎢⎢⎢⎢⎢⎢dp[k][1]dp[k][2]dp[k][3]....dp[k][n]⎤⎦⎥⎥⎥⎥⎥⎥[dp[k][1]dp[k][2]dp[k][3]....dp[k][n]]
那么未修改之前的就是:
⎡⎣⎢⎢⎢⎢⎢⎢dp[0][1]dp[0][2]dp[0][3]....dp[0][n]⎤⎦⎥⎥⎥⎥⎥⎥[dp[0][1]dp[0][2]dp[0][3]....dp[0][n]] = ⎡⎣⎢⎢⎢⎢⎢⎢1−10...001−1...0001...0...............000...−1000...1⎤⎦⎥⎥⎥⎥⎥⎥k[100...00−110...000−11...00..................000...−11]k⎡⎣⎢⎢⎢⎢⎢⎢dp[k][1]dp[k][2]dp[k][3]....dp[k][n]⎤⎦⎥⎥⎥⎥⎥⎥[dp[k][1]dp[k][2]dp[k][3]....dp[k][n]]
这个东西本来是矩阵快速幂解决,但是nn到了10001000,这样的话时间就是O(n3logk)O(n3logk),显然不行,那就打个表出来, 发现了......这个矩阵kk次幂之后A[i][j]A[i][j] = (−1)i−j∗Ci−jk(−1)i−j∗Cki−j,这样从(i,i)(i,i)这个位置往前推,但是组合数很大, 注意CxkCkx可以由Cx−1kCkx−1递推而来。
#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e3 + 10;
const ll mod = 1e9 + 7;
using namespace std;
ll n, m, T, kase = 1, k;
ll ans[maxn], a[maxn], inv[maxn];
ll qmod(ll x, ll n, ll mod) {
ll ans = 1;
for( ; n; n >>= 1) {
if(n & 1) ans = ans * x % mod;
x = x * x % mod;
}
return ans;
}
int main() {
for(ll i = 1; i < maxn; i++) inv[i] = qmod(i, mod - 2, mod);
scanf("%d", &T);
while(T--){
scanf("%lld %lld", &n, &k);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for(int i = 1; i <= n; i++) {
ll now = 1; ans[i] = a[i];
for(int j = i - 1; j >= 1; j--) {
int flag = (i - j) & 1;
int res = (i - j);
now = now * inv[res] % mod;
now = now * (k - res + 1) % mod;
if(flag) ans[i] -= now * a[j];
else ans[i] += now * a[j];
ans[i] %= mod;
}
}
for(int i = 1; i <= n; i++) {
if(ans[i] < 0) ans[i] +=mod;
printf("%lld%c", ans[i], i < n ? ' ' : '\n');
}
}
return 0;
}