https://codeforces.com/contest/1467/problem/D
这题要修改每个a[i]然后得到最后的值,那么肯定就要求出每个a[i]对最后的答案有多少次贡献
cnt[i][j]表示第i步走到j的位置,前缀有多少可能,num[i][j]第i步从j开始走,走完k步,后缀有多少可能
那么在第i步用到a[j]的方案数就是cnt[i][j]*num[i][j]
这个思路有点像求桥的时候正反跑一遍方案数可以用pre[i]*fpre[i]=sum他就是一个必经点
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=5010;
const int mod=1e9+7;
int n,m,k,tot,cas,ans;
int a[maxl];ll sum[maxl];
ll dp[maxl][maxl],num[maxl][maxl],cnt[maxl][maxl];
bool vis[maxl];
char s[maxl];
inline void prework()
{
scanf("%d%d%d",&n,&k,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
}
inline void add(ll &x,ll y)
{
x+=y;
if(x>=mod)
x-=mod;
if(x<0)
x+=mod;
}
inline ll qp(ll a,ll b)
{
ll ans=1,cnt=a;
while(b)
{
if(b&1)
ans=ans*cnt%mod;
cnt=cnt*cnt%mod;
b>>=1;
}
return ans;
}
inline void mainwork()
{
for(int i=1;i<=n;i++)
num[k][i]=1;
for(int i=k;i>=1;i--)
for(int j=1;j<=n;j++)
{
if(j>1)
add(num[i-1][j-1],num[i][j]);
if(j<n)
add(num[i-1][j+1],num[i][j]);
}
for(int i=1;i<=n;i++)
cnt[0][i]=1,add(sum[i],num[0][i]);
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
{
if(j>1)
add(cnt[i][j],cnt[i-1][j-1]);
if(j<n)
add(cnt[i][j],cnt[i-1][j+1]);
add(sum[j],cnt[i][j]*num[i][j]%mod);
}
ll ans=0;
for(int i=1;i<=n;i++)
add(ans,sum[i]*a[i]%mod);
while(m--)
{
int i,x;
scanf("%d%d",&i,&x);
add(ans,-sum[i]*a[i]%mod);
a[i]=x;
add(ans,sum[i]*a[i]%mod);
printf("%lld\n",ans);
}
}
inline void print()
{
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}