1467D. Sum of Paths(妙用dp的含义)

传送门

话说这个 D D D好水…

只要提前预处理每个格子被走过的次数 c n t [ i ] cnt[i] cnt[i]就好了

f [ i ] [ j ] f[i][j] f[i][j]表示走了 i i i步后在点 j j j的方案数

由于起点任选那么有 f [ 0 ] [ i ] = 1 f[0][i]=1 f[0][i]=1

转移为 f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + f [ i − 1 ] [ j + 1 ] f[i][j]=f[i-1][j-1]+f[i-1][j+1] f[i][j]=f[i1][j1]+f[i1][j+1]

那么现在考虑求 c n t [ i ] cnt[i] cnt[i],就是格子 i i i被经过多少次

不妨枚举格子 i i i在第 j j j次经过多少次,累加次数

首先 j j j步到达格子 i i i的方案数是 f [ j ] [ i ] f[j][i] f[j][i],但是到了格子 i i i后还有 k − j k-j kj步可以延续状态

我们需要知道从格子 i i i k − j k-j kj步的方案数,其实就是 f [ k − j ] [ i ] f[k-j][i] f[kj][i]

因为从格子 i i i k − j k-j kj步的方案数等价于走 k − j k-j kj步到达格子 i i i

这是因为不管最初从哪个点出发走 k − j k-j kj步到达 i i i,路径的逆过程就是格子 i i i k − j k-j kj步出去

所以枚举 j j j累加即可 c n t [ i ] + = f [ j ] [ i ] ∗ f [ k − j ] [ i ] cnt[i]+=f[j][i]*f[k-j][i] cnt[i]+=f[j][i]f[kj][i]

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9+7;
const int maxn = 5009;
int n,k,f[maxn][maxn],q,a[maxn],cnt[maxn],ans;
signed main()
{
    
    
	cin >> n >> k >> q;
	for(int i=1;i<=n;i++)	cin >> a[i];
	for(int i=1;i<=n;i++)	f[0][i] = 1;
	for(int i=1;i<=k;i++)
	for(int j=1;j<=n;j++)
	{
    
    
		if( j==1 )	f[i][j] = f[i-1][j+1];
		else if( j==n )	f[i][j] = f[i-1][j-1];
		else	f[i][j] = ( f[i-1][j-1]+f[i-1][j+1] )%mod;
	}
	//从点i走x步有多少种方案 
	for(int i=1;i<=n;i++)
	for(int j=0;j<=k;j++)
		cnt[i] = ( cnt[i]+f[k-j][i]*f[j][i]%mod )%mod;
	for(int i=1;i<=n;i++)	ans = ( ans+cnt[i]*a[i]%mod )%mod;
	while( q-- )
	{
    
    
		int i,x; scanf("%lld%lld",&i,&x);
		ans = ( ans-cnt[i]*a[i]%mod )%mod;
		a[i] = x;
		ans = ( ans+cnt[i]*a[i]%mod )%mod;
		printf("%lld\n",(ans+mod)%mod);
	}
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/112389434