牛客暑假多校 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 }
View Code

 

 

 

 

 

  

posted @ 2018-08-24 09:57  Schenker  阅读(191)  评论(0编辑  收藏  举报