D. Sum of Paths
题意
一共有 n n n 个格子,每个格子都有一个值 a i a_i ai。一开始可以在任意一个格子放置一个机器人,机器人精确的走 k k k 步经过 k + 1 k+1 k+1 个格子,走过一个格子产生 a i a_i ai 的贡献,问所有不同的走法产生的总贡献,有 q q q 次询问,每次询问都可以修改一个格子的值。
题解
先预处理出所有走法每个格子会被走的次数总和,然后每次询问 O ( 1 ) O(1) O(1) 计算即可。
- d p [ i ] [ j ] dp[i][j] dp[i][j] 表示第 j j j 步走到第 i i i 个格子的情况数量;
- 初始化 d p [ i ] [ 0 ] = 1 dp[i][0]=1 dp[i][0]=1 ;
- 转移方程 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + d p [ i + 1 ] [ j − 1 ] dp[i][j]=dp[i-1][j-1]+dp[i+1][j-1] dp[i][j]=dp[i−1][j−1]+dp[i+1][j−1] ,即通过一步从相邻格子转移来;
- 那么走 j j j 步恰好到达第 i i i 个格子的情况数为 d p [ i ] [ j ] dp[i][j] dp[i][j] ,但是一共要走 k k k 步,并且从第 i i i 个格子走 k − j k-j k−j 步的情况数量等于从任意格子走 k − j k-j k−j 步恰好到达第 i i i 个格子的情况,即 d p [ i ] [ k − j ] dp[i][k-j] dp[i][k−j] ,所以次数贡献就是 d p [ i ] [ j ] ⋅ d p [ i ] [ k − j ] dp[i][j]\cdot dp[i][k-j] dp[i][j]⋅dp[i][k−j] 。
- 知道每个格子的贡献次数,那么改变一个格子就可以 O ( 1 ) O(1) O(1) 算出了。
代码
#pragma region
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 5005;
const ll mod = 1e9 + 7;
ll a[maxn];
ll dp[maxn][maxn], cnt[maxn];
int main() {
int n, k, q;
scanf("%d%d%d", &n, &k, &q);
rep(i, 1, n) scanf("%lld", &a[i]), dp[i][0] = 1;
rep(j, 1, k) rep(i, 1, n)
dp[i][j] = (dp[i - 1][j - 1] + dp[i + 1][j - 1]) % mod;
rep(j, 0, k) rep(i, 1, n)
cnt[i] = (cnt[i] + dp[i][j] * dp[i][k - j]) % mod;
ll ans = 0;
rep(i, 1, n) ans = (ans + a[i] * cnt[i]) % mod;
while (q--) {
ll pos, x;
scanf("%lld%lld", &pos, &x);
ans = (ans + ((x - a[pos] + mod) % mod) * cnt[pos]) % mod;
printf("%lld\n", ans);
a[pos] = x;
}
}