题目
给出 n n n个数,有 m m m个操作,每个操作是将 [ L , R ] [L,R] [L,R]之间的数加上 C ( j − L + k , k ) C(j-L+k,k) C(j−L+k,k), L < = j < = R L<=j<=R L<=j<=R最后输出这 n n n个数的值。
题解
虽然我考场上推出了式子但是我还是打的n2暴力(暴力选手qwq- n阶差分可能有点难以理解可以先看一下 三 步 必 杀 ( 二 阶 差 分 ) \color{red}三步必杀(二阶差分) 三步必杀(二阶差分) 三 步 必 杀 题 解 \color{blue}三步必杀题解 三步必杀题解
- 我们要加的序列
( k k ) , ( k + 1 k ) ⋯ ( r − l + k k ) \dbinom{k}{k},\dbinom{k+1}{k}\cdots\dbinom{r-l+k}{k} (kk),(kk+1)⋯(kr−l+k) - 又可以写成
( k 0 ) , ( k + 1 1 ) ⋯ ( r − l + k r − l ) \dbinom{k}{0},\dbinom{k+1}{1}\cdots\dbinom{r-l+k}{r-l} (0k),(1k+1)⋯(r−lr−l+k) - 结合公式
( n m ) = ( n − 1 m ) + ( n − 1 m − 1 ) \dbinom{n}{m}=\dbinom{n-1}{m}+\dbinom{n-1}{m-1} (mn)=(mn−1)+(m−1n−1) - 该序列的一阶差分序列为
( k − 1 0 ) , ( k 1 ) ⋯ ( r − l + k − 1 r − l ) ⇔ ( k − 1 k − 1 ) , ( k k − 1 ) ⋯ ( r − l + k − 1 k − 1 ) \dbinom{k-1}{0},\dbinom{k}{1}\cdots\dbinom{r-l+k-1}{r-l}\Leftrightarrow\dbinom{k-1}{k-1},\dbinom{k}{k-1}\cdots\dbinom{r-l+k-1}{k-1} (0k−1),(1k)⋯(r−lr−l+k−1)⇔(k−1k−1),(k−1k)⋯(k−1r−l+k−1) - 二阶差分序列
( k − 2 0 ) , ( k − 1 1 ) ⋯ ( r − l + k − 2 r − l ) ⇔ ( k − 2 k − 2 ) , ( k − 1 k − 2 ) ⋯ ( r − l + k − 2 k − 2 ) \dbinom{k-2}{0},\dbinom{k-1}{1}\cdots\dbinom{r-l+k-2}{r-l}\Leftrightarrow\dbinom{k-2}{k-2},\dbinom{k-1}{k-2}\cdots\dbinom{r-l+k-2}{k-2} (0k−2),(1k−1)⋯(r−lr−l+k−2)⇔(k−2k−2),(k−2k−1)⋯(k−2r−l+k−2) -
j
j
j阶差分序列
( k − j 0 ) , ( k − j + 1 1 ) , ⋯   , ( r − l + k − j r − l ) ⇔ ( k − j k − j ) , ( k − j + 1 k − j ) ⋯ ( r − l + k − j k − j ) \dbinom{k-j}{0},\dbinom{k-j+1}{1},\cdots,\dbinom{r-l+k-j}{r-l}\Leftrightarrow\dbinom{k-j}{k-j},\dbinom{k-j+1}{k-j}\cdots\dbinom{r-l+k-j}{k-j} (0k−j),(1k−j+1),⋯,(r−lr−l+k−j)⇔(k−jk−j),(k−jk−j+1)⋯(k−jr−l+k−j) - 我们可以发现这样的组合数序列在进行 k + 1 k+1 k+1次差分后全部变为 0 0 0,我们可以在 k + 1 k+1 k+1次差分序列的 l l l位置加上 1 1 1,在 r + 1 r+1 r+1位置减去前面的前缀和即可
- 而
j
j
j阶差分的前
k
k
k位的和等于
j
−
1
j-1
j−1阶差分序列的第
k
k
k个数(
手推一下吧 - 所以第
j
j
j阶序列的前缀和
∑ j = 0 k ( r − l + k − j r − l ) = ( r − l + k − j + 1 k − j + 1 ) \sum_{j=0}^k\dbinom{r-l+k-j}{r-l}=\dbinom{r-l+k-j+1}{k-j+1} j=0∑k(r−lr−l+k−j)=(k−j+1r−l+k−j+1) - 每次消除前缀和对后面的影响即可
c o d e code code
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <list>
#include <map>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int maxn = 100000 + 1000;
const int maxm = 100 + 10;
const int mod = 1000000007;
typedef long long LL;
template <class T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
int n, m;
LL a[maxn];
LL c[maxn][maxm], ans[maxn][maxm];
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("data.in", "r", stdin);
freopen("bf.out", "w", stdout);
init();
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[r-l+k+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("%lld ", ((ans[i][0] + a[i]) % mod + mod) % mod);
}
return 0;
}