admin管理员组

文章数量:1612420

题意:给出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;
}

本文标签: 序列差分CFArraycurious