CF407C Curious Array(n阶差分)

题目

给出 n n n个数,有 m m m个操作,每个操作是将 [ L , R ] [L,R] [L,R]之间的数加上 C ( j − L + k , k ) C(j-L+k,k) C(jL+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)(krl+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)(rlrl+k)
  • 结合公式
    ( n m ) = ( n − 1 m ) + ( n − 1 m − 1 ) \dbinom{n}{m}=\dbinom{n-1}{m}+\dbinom{n-1}{m-1} (mn)=(mn1)+(m1n1)
  • 该序列的一阶差分序列为
    ( 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} (0k1),(1k)(rlrl+k1)(k1k1),(k1k)(k1rl+k1)
  • 二阶差分序列
    ( 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} (0k2),(1k1)(rlrl+k2)(k2k2),(k2k1)(k2rl+k2)
  • 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} (0kj),(1kj+1),,(rlrl+kj)(kjkj),(kjkj+1)(kjrl+kj)
  • 我们可以发现这样的组合数序列在进行 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 j1阶差分序列的第 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=0k(rlrl+kj)=(kj+1rl+kj+1)
  • 每次消除前缀和对后面的影响即可

c o d e code code

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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; 
}


你可能感兴趣的:(题解————题解,基本算法——基本算法,基本算法——差分)