Codeforces Round #695 (Div. 2) D. Sum of Paths(dp)

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[i1][j1]+dp[i+1][j1] ,即通过一步从相邻格子转移来;
  • 那么走 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 kj 步的情况数量等于从任意格子走 k − j k-j kj 步恰好到达第 i i i 个格子的情况,即 d p [ i ] [ k − j ] dp[i][k-j] dp[i][kj] ,所以次数贡献就是 d p [ i ] [ j ] ⋅ d p [ i ] [ k − j ] dp[i][j]\cdot dp[i][k-j] dp[i][j]dp[i][kj]
  • 知道每个格子的贡献次数,那么改变一个格子就可以 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;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43860866/article/details/112504072