codeforces 1467 D. Sum of Paths (dp)
题目链接:https://codeforces.com/contest/1467/problem/D
题目大意:
定义一条好的路径,当且仅当从任意点出发之后恰好经过了 \(k\) 次移动,定义这条路径的权值为经过点权值的总和(可重),进行 \(q\) 次修改,每次将\(a_k\) 改为 \(x\) ,询问此时所有‘好’路径的权值总和.
题解:
考虑每个格子的贡献,设 \(f[i][j]\) 表示第 \(j\) 步走到第 \(i\) 个格子的方案数,\(g[i][j]\) 表示当前是第 \(i\) 步,在第 \(j\) 个格子,可以走出多少个不同的路径
转移十分显然:
\[f[i][j] = f[i-1][j-1] + f[i-1][j+1]
\]
\[g[i][j] = g[i+1][j-1] + g[i+1][j+1]
\]
那么第 \(i\) 个格子对答案的贡献就是
\[a_i* \sum_{j=0}^kf[j][i]*g[j][i]
\]
修改操作每次在上一次的答案一减一增即可
时间复杂度 \(O(n^2 + q)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5010;
const int M = 1000000007;
int n, k, q;
int a[maxn];
int f[maxn][maxn], g[maxn][maxn];
int c[maxn];
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
n = read(), k = read(), q = read();
for(int i = 1 ; i <= n ; ++i) a[i] = read();
for(int i = 1 ; i <= n ; ++i) f[0][i] = 1, g[k][i] = 1;
for(int i = 1 ; i <= k ; ++i){
for(int j = 1 ; j <= n ; ++j){
f[i][j] = (f[i - 1][j - 1] + f[i - 1][j + 1]) % M;
}
}
for(int i = k - 1 ; i >= 0 ; --i){
for(int j = 1 ; j <= n ; ++j){
g[i][j] = (g[i + 1][j - 1] + g[i + 1][j + 1]) % M;
}
}
for(int i = 0 ; i <= k ; ++i){
for(int j = 1 ; j <= n ; ++j){
c[j] = (c[j] + 1ll * f[i][j] * g[i][j] % M) % M;
}
}
int ans = 0;
for(int i = 1 ; i <= n ; ++i) ans = (ans + 1ll * c[i] * a[i] % M) % M;
int x, y;
for(int i = 1 ; i <= q ; ++i){
x = read(), y = read();
ans = ((ans - 1ll * a[x] * c[x] % M) % M + M) % M;
a[x] = y;
ans = (ans + 1ll * a[x] * c[x] % M) % M;
printf("%d\n", ans);
}
return 0;
}