CF1467D Sum of Paths

传送门

题目大意

数轴上有 n n n 个点,一个机器人从任意位置出发,每个时刻任意向左或者向右,到达一个位置就加上这个位置的分数,求最后走 k k k 步所有可能的分数之和。

并且有 q q q 次询问,每次修改一个点权。

Solution

显然不能直接做。所以考虑拆开算贡献。

对于一个点,我们考虑会在路径中出现多少次。考虑用 d p dp dp 算。

c n t i , j cnt_{i,j} cnti,j 为第 i i i 步的时候走到 j j j 号点的路径数,那么有:

c n t i , j = c n t i − 1 , j − 1 + c n t i − 1 , j + 1 cnt_{i,j}=cnt_{i-1,j-1}+cnt_{i-1,j+1} cnti,j=cnti1,j1+cnti1,j+1

但是我们不知道到达第 i i i 号点的时候是路径的第几部,所以考虑再设一个 c n t i , j ′ cnt'_{i,j} cnti,j 表示从 j j j 号节点出发,走 i i i 步的路径总数,结果发现递推式和 c n t cnt cnt 一模一样,那就直接用 c n t cnt cnt 了。这样递推是 O ( n 2 ) O(n^2) O(n2) 的可以接受。

然后考虑用 c n t cnt cnt 来求出一个点在所有路径中出现的次数。

枚举点 i i i 在路径中是第 j j j 个点,那么有( m u l mul mul 就表示出现次数):

m u l = ∑ j = 0 k c n t j , i × c n t k − j , i mul=\sum_{j=0}^kcnt_{j,i}\times cnt_{k-j,i} mul=j=0kcntj,i×cntkj,i

于是我们成功求出每个点出现的次数,然后乘上点的权值就是最后对答案的贡献了。

至于修改,用树状数组或者线段树维护一下就可以了。

复杂度是 O ( n 2 + q log ⁡ n ) O(n^2+q\log n) O(n2+qlogn),可以过。

Code

#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
using namespace std;
const int MAXN=5010;
const ll MOD=1e9+7;
ll cnt[MAXN][MAXN],a[MAXN],mul[MAXN];
ll tr[MAXN];
int n;
int lbt(int x){return x&(-x);}
void upd(int x,ll v){
	for(int i=x;i<=n;i+=lbt(i))
		tr[i]=(tr[i]+v)%MOD;
}
ll ask(int x){
	ll ret=0;
	for(int i=x;i;i-=lbt(i))
		ret=(ret+tr[i])%MOD;
	return ret;
}
void solve(){
	int k,Q;
	scanf("%d%d%d",&n,&k,&Q);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]),cnt[0][i]=1;
	for(int i=1;i<=k;i++){
		for(int j=1;j<=n;j++)
			cnt[i][j]=(cnt[i-1][j-1]+cnt[i-1][j+1])%MOD;
	}
	for(int i=1;i<=n;i++)
		for(int j=0;j<=k;j++)
			mul[i]=(mul[i]+cnt[j][i]*cnt[k-j][i]%MOD)%MOD;
	for(int i=1;i<=n;i++)
		upd(i,mul[i]*a[i]%MOD);
	int p;ll x;
	while(Q--){
		scanf("%d%lld",&p,&x);
		upd(p,(MOD-a[p]*mul[p]%MOD)%MOD);
		a[p]=x;
		upd(p,a[p]*mul[p]%MOD);
		printf("%lld\n",ask(n)%MOD);
	}
}
int main()
{
//	int T;
//	for(scanf("%d",&T);T--;)
		solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值