版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/du_lun/article/details/81841599
假如a[0][1]=1,那他对后面的影响如图所示,斜着看可以发现,是杨辉三角,假如k=3,x=3,a[0][1]对他的影响是C(4, 2),a[0][2]对他的影响是C(3,2),a[0][3]对他的影响是C(2,2);所以a[0][i]对他的影响是C(k+x-1-i,k-1),,我们将式子转化为,这样对于后面的\sum可以通过树状数组维护前缀和。对于负数的组合数,,对于组合数递推公式仍然满足。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
const int mo=1e9+7;
int n, m, k, x;
ll y, s[50][N];
ll inv[N];
void init(){
inv[1]=1;
for(int i=2; i<N; i++)
inv[i]=inv[mo%i]*(mo-mo/i)%mo;
}
void upd(int id, int x, ll v){
for(;x<N;x+=x&-x){
s[id][x]=(s[id][x]+v+mo)%mo;
}
}
ll sum(int id, int x){
ll ret=0;
for(; x>0; x-=x&-x)
ret=(ret + s[id][x])%mo;
return ret;
}
int main(){
init();
scanf("%d%d%d", &n, &m, &k);
int o;
while(m--){
scanf("%d", &o);
if(o==0){
ll u=1;
scanf("%d%lld", &x, &y);
for(int i=0; i<k; i++){
upd(i, x, u*y%mo);
u=u*(k-1-x-i)%mo*inv[i+1]%mo;
}
}
else{
scanf("%d", &x);
ll ans=0, u=1;
for(int i=0; i<k; i++){
ans=(ans+u*sum(k-1-i, x)%mo)%mo;
u=u*(x-i)%mo*inv[i+1]%mo;
if(u<0) u+=mo;
}
//cout<<"******"<<endl;
printf("%lld\n", ans);
}
}
return 0;
}
另一种分块的思想也很巧妙,题目给的时间是3秒,总复杂度3e8肯定没问题,1e5次操作,我们如果将更新操作累加到1000次再暴力更新,暴力更新复杂度是O(n*k),最多1e2次更新,总的时间复杂度是1e5*1e2*40=1e8左右,如果是询问,因为1000次以内不更新,如果有询问,就看哪个更新对询问的位置产生影响,这样的话复杂度是1000,最多1e5的复杂度,所以分块时间会优化特别多。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
const int mo=1e9+7;
int n, m, k, x, block;
ll y, s[N], a[N], dp[2][N];
struct Qu{
ll v, x;
}Q[N];
ll inv[N], finv[N], fac[N];
void init(){
inv[1]=finv[0]=finv[1]=fac[0]=fac[1]=1;
for(int i=2; i<N; i++){
inv[i]=inv[mo%i]*(mo-mo/i)%mo;
fac[i]=1ll*i*fac[i-1]%mo;
}
for(int i=2; i<N; i++)
finv[i]=finv[i-1]*inv[i]%mo;
}
ll C(ll n, ll m){
if(n<m) return 0;
return fac[n]*finv[m]%mo*finv[n-m]%mo;
}
ll query(int x){
ll sum=s[x];
for(int i=1; i<=block; i++){
//cout<<Q[i].v<<endl;
if(Q[i].x<=x)
sum=(sum+C(x-Q[i].x+k-1, k-1)*Q[i].v)%mo;
}
return sum;
}
void upd(){
block=0;
int f=0;
for(int i=1; i<=n; i++) dp[0][i]=a[i];
for(int i=1; i<=k; i++){
f^=1;
dp[f][1]=dp[f^1][1];
for(int j=2; j<=n; j++){
dp[f][j]=(dp[f][j-1]+dp[f^1][j])%mo;
}
}
for(int i=1; i<=n; i++) s[i]=dp[f][i];
}
int main(){
init();
scanf("%d%d%d", &n, &m, &k);
int o;
while(m--){
scanf("%d", &o);
if(o==0){
++block;
scanf("%lld%lld", &Q[block].x, &Q[block].v);
//cout<<Q[block].x<<" "<<Q[block].v<<endl;
a[Q[block].x]+=Q[block].v;
a[Q[block].x]%=mo;
if(block>=2000)
upd();
}
else{
scanf("%d", &x);
//printf("%lld\n", s[x]);
printf("%lld\n", query(x));
}
}
return 0;
}