传送门
话说这个 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[i−1][j−1]+f[i−1][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 k−j步可以延续状态
我们需要知道从格子 i i i走 k − j k-j k−j步的方案数,其实就是 f [ k − j ] [ i ] f[k-j][i] f[k−j][i]
因为从格子 i i i走 k − j k-j k−j步的方案数等价于走 k − j k-j k−j步到达格子 i i i
这是因为不管最初从哪个点出发走 k − j k-j k−j步到达 i i i,路径的逆过程就是格子 i i i走 k − j k-j k−j步出去
所以枚举 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[k−j][i]
#include
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);
}
}