题目大意
给出一个 n n n维数组 a 1 , a 2 , ⋯ , a n a_1,a_2,\cdots,a_n a1,a2,⋯,an,
定义一条长度为
k
k
k的路径如下:
从一个点
c
0
c_0
c0出发,可以向左一步到
c
0
−
1
c_0-1
c0−1(当前不在最左边),向右走一步到
c
0
+
1
c_0+1
c0+1(当前不在最右边),可以走重复点。
记通过第
i
i
i次移动之后到达的位置为
c
i
c_i
ci,则
c
0
,
c
1
,
⋯
,
c
k
c_0,c_1,\cdots,c_k
c0,c1,⋯,ck就称为一条合法路径。
定义该条合法路径的权值为 a c 0 + a c 1 + ⋯ + a c k a_{c_0}+a_{c_1}+\cdots+a_{c_k} ac0+ac1+⋯+ack
并有 q q q次修改操作,每次修改一个 a x a_x ax的权值。
问所有合法路径的权值和。
时间限制
3s
数据范围
n
≤
5000
n\le5000
n≤5000
q
≤
2
×
1
0
5
q\le 2\times10^5
q≤2×105
题解
不难发现,
n
n
n与
q
q
q并不在一个数量级上,因此可以猜测整体的时间复杂度应该是与
n
n
n相关。
要计算最终的答案,其实并不需要写出每条合法路径,只需要统计每个点在合法路径上出现了多少次。
然后通过简单的计算,就可以得到答案了。
不妨设
f
i
,
j
f_{i,j}
fi,j表示经过了
i
i
i次移动,到了
j
j
j这个地方的方案数,
初始化就是
f
0
,
j
=
1
f_{0,j}=1
f0,j=1。
现在可以枚举一个位置是第
i
i
i次移动后抵达的,如果要计算它的方案数,显然还要从它出发,移动
k
−
i
k-i
k−i到达任意一个位置的方案数。
此时,再重新审视一下
f
i
,
j
f{i,j}
fi,j的含有,如果把转移过程逆着看,就会发现它就是刚才需要的这个含义。
Code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
#define G getchar
#define ll long long
using namespace std;
int read()
{
char ch;
for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());
int n = 0 , w;
if (ch == '-')
{
w = -1;
ch = G();
} else w = 1;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n * w;
}
const int N = 5003;
const int mo = 1000000007;
int f[N][N] , s[N];
int n , k , m , x;
ll a[N] , ans , tmp , _2[N] , _3[N];
ll calc (int x , int y)
{
ll tmp = _2[k - x];
int t = min (k -x - (y - 1) , k - x);
if (t > 0) tmp = tmp - _3[t - 1];
if (tmp < 0) tmp = tmp + mo;
t = min (k -x - (n - y) , k - x);
if (t > 0) tmp = tmp - _3[t - 1];
if (tmp < 0) tmp = tmp + mo;
return tmp;
}
int main()
{
//freopen("f.in","r",stdin);
//freopen("2.txt","w",stdout);
_2[0] = _3[0] = 1;
for (int i = 1 ; i < N ; i++)
{
_2[i] = _2[i - 1] * 2 % mo;
_3[i] = _3[i - 1] * 3 % mo;
}
n = read();
k = read();
m = read();
for (int i = 1 ; i <= n; i++)
{
f[0][i] = 1;
s[i] = 0;
}
for (int i = 1 ; i <= k ; i++)
for (int j = 1 ; j <= n ; j++)
{
tmp = f[i - 1][j - 1] + f[i - 1][j + 1];
f[i][j] = (tmp < mo ? tmp : tmp - mo);
}
for (int i = 0 ; i <= k ; i++)
for (int j = 1 ; j <= n ; j++)
{
tmp = s[j] + (ll)f[i][j] * f[k - i][j] % mo;
s[j] = (tmp < mo ? tmp : tmp - mo);
}
for (int i = 1 ; i <= n; i++)
a[i] = read();
ans = 0;
for (int i = 1 ; i <= n ; i++)
{
tmp = ans + s[i] * a[i] % mo;
ans = (tmp < mo ? tmp : tmp - mo);
}
for ( ; m ; m--)
{
x = read();
tmp = a[x];
a[x] = read();
tmp = a[x] - tmp;
if (tmp < 0) tmp = tmp + mo;
ans = (ans +s[x] * tmp % mo);
if (ans >= mo) ans = ans - mo;
printf("%lld\n", ans);
}
return 0;
}