【CF1467D】Sum of Paths 题解

题目链接

题意简介

一条线段上有 n 个点,机器人每次只能移动到自己相邻的点上,且不能离开这 n 个点。每个点都有分数,分别是 (a_1,a_2,...,a_n)。 机器人将从任意一个点开始时,在线段上移动 k 次,每到一个点(包括起始点和重复路过的点),机器人的总分就会加上该点的分数。

现在,我们将对这条线段作 q 次单点点权修改,试求出所有的移动方案的机器人总分的总和。

思路分析

很明显这是一道计数问题。不难看出,每次修改后,每个点在所有方案中一共出现的次数 (cnt_i) 是不会改变的。我们只需要先求出 (cnt_i),维护答案 (sum cnt_i imes a_i) 就行了。

(f(step,point)) 表示已经走了 step 步,且最后一步恰好为点 point 的方案数。显然的,我们可以得出:(f(s,p)=f(s-1,p-1)+f(s-1,p+1))(f(0,p)=1)

而这个 (f(s,p)) 换一种换一种理解方式:可以表示从点 p 出发,走 s 步的方案数。

于是,我们可以用 (f(s,p)*f(k-s,p)) 表示在完整的走 k 步的方案中,第 s 步为点 p 的方案数。

而每个点都可能出现在任何一步中,所以,(cnt_i=sum^k_{s=0} f(s,i)*f(k-s,i))

至此,问题解决。接下来只要求出一次 (res = sum cnt_i imes a_i) 之后,每次修改把答案更改为 (res+cnt_i*(x-a_i)) 就行了。

代码库

#include <cstdio>
typedef long long ll;
const ll mod=1e9+7,N=5e3+5;
ll n,k,q,f[N][N],a[N],cnt[N],tot;
int main(){
    scanf("%lld%lld%lld",&n,&k,&q);
    for(int i=1;i<=n;i++) scanf("%lld",a+i),f[i][0]=1;
    for(int t=1;t<=k;t++){
        f[1][t]=f[2][t-1]; f[n][t]=f[n-1][t-1];
        for(int i=2;i<n;i++) f[i][t]=(f[i-1][t-1]+f[i+1][t-1])%mod;
    }
    for(int i=1;i<=n;i++){
        for(int t=0;t<=k;t++) cnt[i]=(cnt[i]+f[i][t]*f[i][k-t]%mod)%mod;
        tot=(tot+cnt[i]*a[i]%mod)%mod;
    }
    while(q--){
        ll i,x; scanf("%lld%lld",&i,&x);
        tot=(tot+mod-cnt[i]*a[i]%mod+cnt[i]*x%mod)%mod;
        a[i]=x; 
        printf("%lld
",tot);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Qing-LKY/p/CF1467D-solution.html