CF407C.Curious Array k階差分
阿新 • • 發佈:2021-10-30
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}\\ \]二階差分
\(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); }