• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
dwtfukgv
博客园    首页    新随笔    联系   管理    订阅  订阅
CodeForces 1467D Sum of Paths (动态规划)

CodeForces 1467D Sum of Paths

题意

有一条直线,直线上有 n(n <= 5000) 个点,每个点有一个值,你可以选择在任意点出发,移动 k(k <= 5000) 步,只能向左或向右移动,但是可以多次经过同一个点,所有可能出现的路径称好路径。下面有 q(q <= 200000) 个询问,每次询问修改一个点的值,同时需要你输出所有好路径经过的点的值的总和。

输入

5 1 5
3 5 1 4 2
1 9
2 4
3 6
4 6
5 2

输出

62
58
78
86
86

样例解释

该样例可能出现的所有好路径为,(1,2),(2,1),(2,3),(3,2),(3,4),(4,3),(4,5),(5,4)(1,2),(2,1),(2,3),(3,2),(3,4),(4,3),(4,5),(5,4)。然后每次询问将其中一个点的值改变,然后输出所有好路径的经过的所有点的值的总和。

解析

首先根据题意,很容易能够想出计算所有路径的条数的方式,使用动态规划的思想,\(dp[i][j]\) 表示从任意点出发,移动 \(i\) 步并且停在点 \(j\) 时的所有路径的条数。状态转移方程也比较简单,\(dp[i][j] = dp[i-1][j-1] + dp[i-1][j+1]\) ,这样就可以计算所有的好路径。

但是如果每次查询都重新计算,那么肯定会超时,所以我们可以计算出所有的好路径中一共经过某个点的次数,这样每次修改,只要将修改后与修改前的值再乘以出现的次数,就是答案。

所以问题就是需要去求出所有好路径中经过某个点的次数,首先先来枚举一点 \(j\),再来看定义的动态规划 \(dp[i][j]\) 正向来看表示从任意点出发,移动 \(i\) 步并且停在点 \(j\) 时的所有路径的条数,那么反向来看呢,可以表示为从 \(j\) 点出发,移动 \(i\) 步,到达任意点的所有路径的条数。所以对于移动 \(i\) 步到 \(j\) 点的路径对 \(j\) 点的贡献次数就是 \(dp[i][j] * dp[k-i][j]\) ,可以理解成两半路径拼起来的。刚才这个是对移动 \(i\) 步到 \(j\) 点的路径对 \(j\) 点的贡献次数,所以对于所有 \(j\) 点的贡献次数为 \(\sum_{i=0}^kdp[i][j]*dp[k-i][j]\) 。所以再次需要 \(O(n^2)\) 复杂度来求出每个点的贡献次数,这样就解决了该题目。

代码

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <ctime>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#include <numeric>
#include <unordered_map>
#define debug() puts("++++")
#define print(x) cout<<"====== "<<(x)<<" ====="<<endl;
// #define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
#define _mod(x) ((x) % mod + mod) % mod
#define sz size()
#define be begin()
#define ed end()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
// #define all 1,n,1
#define FOR(i,n,x)  for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.in", "r", stdin)
#define freopenw freopen("out.out", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e17;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-12;
const int maxn = 5000 + 7;
const int maxm = 2000000 + 7;
const LL mod = 1e9 + 7;
const int dr[] = {-1, 1, 0, 0, 1, 1, -1, -1};
const int dc[] = {0, 0, 1, -1, 1, -1, 1, -1};
const P null = P(-1, -1);
int n, m;

inline bool is_in(int r, int c) {
  return r >= 0 && r < n && c >= 0 && c < m;
}
inline int read_int(){
  int x;  scanf("%d", &x);  return x;
}

LL dp[maxn][maxn], sum[maxn];
int a[maxn];


int main(){
  int q;
  scanf("%d %d %d", &n, &m, &q);
  for(int i = 1; i <= n; ++i){
    scanf("%d", a + i);
    dp[0][i] = 1;
  }

  for(int i = 1; i <= m; ++i){
    for(int j = 1; j <= n; ++j){
      dp[i][j] = (dp[i-1][j-1] + dp[i-1][j+1]) % mod;
    }
  }
  LL ans = 0;
  for(int i = 1; i <= n; ++i){
    for(int j = 0; j <= m; ++j){
      sum[i] = (sum[i] + dp[j][i] * dp[m-j][i]) % mod;
    }
    ans = (ans + sum[i] * a[i]) % mod;
  }

  while(q--){
    int x, i;  scanf("%d %d", &i, &x);
    int det = x - a[i];
    a[i] = x;
    ans = _mod(ans + det * sum[i]);
    cout << ans << endl;
  }

  return 0;
}
posted on 2021-06-18 11:12  dwtfukgv  阅读(62)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3