首页 > 技术文章 > CF407C.Curious Array k阶差分

hznumqf 2021-10-30 11:39 原文

CF407C.Curious Array k阶差分

题意

给定长度为\(n\)的数组\(a\),进行\(m\)次修改,每次修改给定\(l ,r,k\),给区间\([l,r]\)加上\(\binom{j - l_i + k_i}{k_i}\)

求所有修改以后每个数的值

\[1 \leq n,m\leq10^5\\ 0\leq a_i \leq 10^9\\ 1\leq l_i \leq r_i \leq n,0\leq k \leq 100 \]

分析

尝试从\(k\)比较小来入手,显然给定的\(a\)初始大小我们并不关心

考虑\(a\)数组的差分数组

1阶差分

\[\binom{k-1}{k-1},\binom{k}{1}...\binom{r-l+k-1}{k-1}\\ \]

二阶差分

\[\binom{k-2}{k-2},\binom{k-1}{k-2}...\binom{r-l+k-2}{k-2} \]

\(n\)阶差分

\[\binom{k-n}{k-n},\binom{k-n+1}{k-n}...\binom{k-l+k-n}{k-n} \]

如果能够维护\(n\)阶差分数组,就可以最后对差分数组做前缀和还原出原数组,容易发现最多进行\(k+1\)次差分后全部变为0,再注意维护r+1$的位置

他们的和就是\(\sum_{i=0}^k\binom{r-l+k-i}{r-l} = \binom{r-l+k-i+1}{k-i+1}\)

代码

#include<bits/stdc++.h>
#define fi first
#define se second
#define pii pair<ll,int>
using namespace std;
typedef long long ll;
typedef vector<int> VI;

inline ll rd(){
    ll x;
    scanf("%lld",&x);
    return x;
}

const int MOD = (int)1e9 + 7;

inline void add(int &a,int b){
    a += b;
    if(a >= MOD) a -= MOD;
}

inline int mul(int a,int b){
    return (ll)a * b % MOD;
}

inline int ksm(int a,int b = MOD - 2,int m = MOD){
    int ans = 1;
    int base = a;
    while(b){
        if(b & 1) ans = mul(ans,base);
        base = mul(base,base);
        b >>= 1;
    }
    return ans;
}


const int maxn = 2e5 + 5;

int iv[maxn];
int fac[maxn];

inline int C(int n,int m){
    if(n < m) return 0;
    return mul(fac[n],mul(iv[m],iv[n - m]));
}

int ans[maxn][105];
int a[maxn];

int main(){
    fac[0] = iv[0] = 1;
    for(int i = 1;i < maxn;i++)
        fac[i] = mul(fac[i - 1],i);
    iv[maxn - 1] = ksm(fac[maxn - 1]);
    for(int i = maxn - 2;i;i--)
        iv[i] = mul(iv[i + 1],i + 1);
    int n = rd();
    int m = rd();
    for(int i = 1;i <= n;i++)
        a[i] = rd();
    for(int i = 0;i < m;i++){
        int l = rd();
        int r = rd();
        int k = rd();
        for(int j = 0;j <= k;j++){
            add(ans[l][j],C(k,k - j));
        }
        for(int j = 0;j <= k;j++){
            add(ans[r + 1][j],MOD - C(r - l + k + 1,k - j));
        }
    }
    for(int i = 1;i < n;i++)
        for(int j = 101;j >= 1;j--)
            add(ans[i + 1][j - 1],(ans[i][j] + ans[i][j - 1]) % MOD);
    for(int i = 1;i <= n;i++)
        printf("%d ",(ans[i][0] + a[i]) % MOD);
}

推荐阅读