hdu 6333 Harvest of Apples 莫队

题意:  给你一个n,m 让你求C(n,0)+C(n,1)+...+C(n,m)  的值

一开始直接想到二项式方程 但发现2^n=C(n,0)+C(n,1)+...+C(n,n)  没什么用

后来发现队友开始吹  发现   用s(n,m)表示C(n,0)+C(n,1)+...+C(n,m)  那么

s(n,m)=2*s(n-1,m)-c(n-1,m);

s(n,m)=s(n,m-1)+c(n,m);

也就是说知道一个s(n,m)就能O(1)求出s(n+1,m),s(n-1,m),s(n,m+1),s(n,m-1)

队友一看就想到用莫队写    然而tle了    一直没做出来  看了题解才知道  我们每次用逆元时都 log(n)处理了 其实可以O(n)全部预处理出来。

接下来是官方代码

#include <bits/stdc++.h>
using namespace std;

const int N = 200000;
const int MOD = 1000000007;
struct query
{
    int n, k, i;
} Q[N];
int T;
vector <query> lst[N];
int cnt, mx, chunk;
int fac[N], inv[N], res[N], in_chunk[N];
int powi(int a, int b)
{
    int c = 1;
    for (; b; b >>= 1, a = 1ll * a * a % MOD)
        if (b & 1) c = 1ll * c * a % MOD;
    return c;
}
int C(int a, int b)
{
    return 1ll * fac[a] * inv[b] % MOD * inv[a - b] % MOD;
}
int comp(query a, query b)
{
    return a.n < b.n;
}
int main()
{
    mx = 100000;
    fac[0] = 1;
    for (int i = 1; i <= mx; ++ i)                                      //预处理100000内的阶乘
    {
        fac[i] = 1ll * fac[i - 1] * i % MOD;
    }
    inv[mx] = powi(fac[mx], MOD - 2);
    for (int i = mx - 1; ~i; -- i)                                      //预处理100000内的逆元  从最大的开始求
    {
        inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
    }
    chunk = sqrt(mx);                                                   // 每块的大小
    cnt = 1;
    for (int i = 1; i <= mx; i += chunk, ++ cnt)                        // 开始分块  标记每个位置属于哪块
        for (int j = i; j < i + chunk && j <= mx; ++ j)
            in_chunk[j] = cnt;
    cnt --;
    scanf("%d", &T);
    for (int i = 1; i <= T; ++ i)
    {
        scanf("%d%d", &Q[i].n, &Q[i].k), Q[i].i = i;
        lst[in_chunk[Q[i].k]].push_back(Q[i]);
    }
    for (int i = 1; i <= cnt; ++ i) if (lst[i].size())
    {
        sort(lst[i].begin(), lst[i].end(), comp);
        int val = 0, in = lst[i][0].n, ik = -1;
        for (int j = 0; j < lst[i].size(); ++ j)
        {
            while (in < lst[i][j].n) val = (0ll + val + val + MOD - C(in ++, ik)) % MOD;       //s(n,m)=2*s(n-1,m)-c(n-1,m);
            while (ik < lst[i][j].k) val = (val + C(in, ++ ik)) % MOD;                          //s(n,m)=s(n,m-1)+c(n,m);
            while (ik > lst[i][j].k) val = (val + MOD - C(in, ik --)) % MOD;                    //s(n,m-1)=s(n,m)-c(n,m);
            res[lst[i][j].i] = val;
        }
    }
    for (int i = 1; i <= T; ++ i) printf("%d\n", res[i]);
}

猜你喜欢

转载自blog.csdn.net/lkaicheng/article/details/81347185