题意:给出n个数,有m个操作,每个操作是将[L,R]之间的数加上C(j-L+k,k),L<=j<=R,最后输出这n个数的值。
思路:比赛的时候拿线段树写了写,最终好像还是不太对。。。后来看群里讨论说这是差分序列什么的,就去虔诚地学了下……弄懂以后这题就不难了。首先我们知道C(x+1,k)-C(x,k)=C(x,k-1),可以发现,每次做差后k就会减1。由差分序列的性质可以知道k阶以上的差分序列全为0,可以求出在L位置的前k阶差分序列,那么就可以推出下一个数的差分序列,然后再R+1的位置减去就行了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+1000;
const int maxm=100+10;
const int mod=1000000007;
ll C[maxn][maxm],ans[maxn][maxm];
int a[maxn];
void init()
{
C[0][0]=1;
for(int i=1;i<maxn;++i)
{
C[i][0]=1;
for(int j=1;j<=i&&j<maxm;++j)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
int l,r,k;
while(m--)
{
scanf("%d%d%d",&l,&r,&k);
for(int i=0;i<=k;++i) ans[l][i]=(ans[l][i]+C[k][k-i])%mod;
for(int i=0;i<=k;++i) ans[r+1][i]=(ans[r+1][i]-C[k+r-l+1][k-i])%mod;
}
for(int i=1;i<n;++i)
for(int j=101;j>=1;--j)
ans[i+1][j-1]=(ans[i+1][j-1]+ans[i][j]+ans[i][j-1])%mod;
for(int i=1;i<=n;++i)
printf("%I64d ",((ans[i][0]+a[i])%mod+mod)%mod);
printf("\n");
return 0;
}