牛客暑假多校 H Prefix sum
题意:
现在有一个2维矩阵, 初始化为0。 并且这个矩阵是及时更新的。 dp[i][j] = dp[i-1][j] + dp[i][j-1];
现在有2种操作:
0 x y dp[1][x] += y
1 x 查询dp[k][x]的值。
题解:
神奇的分块算法。
首先我们可以发现 如果在一个 x 的位置加上了值 y 那么 在 x' 的位置加上的值是 从 (1, x) 走到 (k,x')的方案数* y, 只能向下向右移动。
现在我们有2种最暴力的做法:
1 每次更新都暴力更新整个矩阵 然后o1得到结果
2 每次都把添加的数存一下 然后询问的时候通过组合数去找到答案。
这两种做法复杂度都很爆炸。
但是 如果把这2种做法结合一下, 每次都把添加的值存起来,然后询问的时候通过组合数去找答案, 然后当存了的数大于一定的数目的时候再暴力更新整个矩阵。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define lch tr[x].son[0] 12 #define rch tr[x].son[1] 13 #define max3(a,b,c) max(a,max(b,c)) 14 #define min3(a,b,c) min(a,min(b,c)) 15 typedef pair<int,int> pll; 16 const int inf = 0x3f3f3f3f; 17 const LL INF = 0x3f3f3f3f3f3f3f3f; 18 const LL mod = (int)1e9+7; 19 const int N = 1e5 + 100; 20 int F[N], Finv[N], inv[N];/// F是阶层 Finv是逆元的阶层 21 void init(){ 22 inv[1] = 1; 23 for(int i = 2; i < N; i++) 24 inv[i] = (mod - mod/i) * 1ll * inv[mod % i] % mod; 25 F[0] = Finv[0] = 1; 26 for(int i = 1; i < N; i++){ 27 F[i] = F[i-1] * 1ll * i % mod; 28 Finv[i] = Finv[i-1] * 1ll * inv[i] % mod; 29 } 30 } 31 int comb(int n, int m){ /// C(n,m) 32 if(m < 0 || m > n) return 0; 33 return F[n] * 1ll * Finv[n-m] % mod * Finv[m] % mod; 34 } 35 int n, m, k, op, x, y; 36 int dp[55][N]; 37 int add[N]; 38 vector<pll> vc; 39 int query(int x){ 40 int ret = dp[k][x]; 41 for(int i = 0; i < vc.size(); i++){ 42 if(vc[i].fi > x) continue; 43 ret = (ret + 1ll * vc[i].se * comb(k-1+x-vc[i].fi,k-1)) % mod; 44 } 45 return ret; 46 } 47 void build(){ 48 //memset(add, 0, sizeof(add)) 49 //add[1] += dp[1][1]; 50 for(int i = 0; i < vc.size(); i++){ 51 x = vc[i].fi, y = vc[i].se; 52 add[x] = (add[x] + y) % mod; 53 } 54 vc.clear(); 55 for(int i = 1; i <= n; i++){ 56 dp[1][i] = (dp[1][i-1] + add[i]) % mod; 57 //add[i] = 0; 58 } 59 for(int i = 2; i <= k; i++) 60 for(int j = 1; j <= n; j++) 61 dp[i][j] = (dp[i-1][j] + dp[i][j-1]) % mod; 62 } 63 int main(){ 64 init(); 65 scanf("%d%d%d", &n, &m, &k); 66 while(m--){ 67 scanf("%d", &op); 68 if(op){ 69 scanf("%d", &x); 70 printf("%d\n",query(x)); 71 } 72 else{ 73 scanf("%d%d", &x, &y); 74 vc.pb(pll(x,y)); 75 if(vc.size() == 2000) 76 build(); 77 } 78 } 79 return 0; 80 }