HDU6333 Harvest of Apples 莫队

Problem Description 
There are n apples on a tree, numbered from 1 to n. 
Count the number of ways to pick at most m apples.

Input 
The first line of the input contains an integer T (1≤T≤105) denoting the number of test cases. 
Each test case consists of one line with two integers n,m (1≤m≤n≤105).

Output 
For each test case, print an integer representing the number of ways modulo 109+7.

Sample Input 

5 2 
1000 500

Sample Output 
16 
924129523

题意 求出sigma(C(n,0)-C(n,m))

思考:根据官方题解

我们可以取一些定点,然后每次查询就通过离要查询状态最近的点出发。然后暴力的更新到所需要的状态。 
所以如果状态能够线性处理出来的话,这个问题就很好解决了。 
因此考虑离线处理。 
按照以n为第一关键字 m为第二关键字 排序 
思考:如何对于每个 n-1行的前缀和 在能接受的时间代价内求得第n行的前缀和。 
定义 T(i,j) 为 sigma(C(i,0)-C(i,j)) 那么 T(i,j)=2*T(i-1,j)-C(i-1,j) 
这样,状态的转移也可以线性的完成了。 

代码:
 

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int MAX=1e5+10;
LL inv[MAX];
LL fac[MAX];
const int MOD=1e9+7;
LL quickpow(LL a,LL b){
    LL ans=1;
    while(b){
        if(b&1){
            ans=(ans*a)%MOD;
        }
        a=(a*a)%MOD;
        b>>=1;
    }
    return ans;
}
void init(){
    fac[0] = 1;
    for(LL i=1;i<MAX;i++){
        fac[i] = i * fac[i-1]  % MOD;
    }
    inv[MAX - 1] = quickpow(fac[MAX - 1],MOD - 2);
    for(int i = MAX - 2;i >= 0;i--)
        inv[i] = inv[i + 1] * (i + 1) % MOD;
}
class Node{
public:
    int id,n,m;
    bool operator < (const Node &b) const{
        if(n==b.n){
            return m<b.m;
        }
        return n<b.n;
    }
};
LL C(long long n,long long m){
    if(n<0 || m< 0 ) return 0;
    if(n<m) return 0;
    return (fac[n]%MOD*inv[n-m]%MOD*inv[m]%MOD)%MOD;
}
Node node[MAX];
LL pre[MAX];
int nowceng=1;
int tot=1;
void up(){
    for(int i=1;i<=tot;i++){
        pre[i]=pre[i]*2ll-C(nowceng,300*(i));
        pre[i]=(pre[i]+MOD)%MOD;
    }
}
LL ans[MAX];
int main(){
    int T;
    init();
    scanf("%d",&T);
    for(int i=0;i<T;i++){
        scanf("%d %d",&node[i].n,&node[i].m);
        node[i].id=i;
    }
    sort(node,node+T);
    pre[0]=1;
    nowceng=1;
    tot=0;
    for(int i=0;i<T;i++){
        while(nowceng<node[i].n){
            up();
            nowceng++;
        }
        while(node[i].m>tot*300 && (tot+1)*300 <= nowceng){
            pre[tot+1]=pre[tot];
            tot++;
            for(int i=1;i<=300;i++){
                pre[tot]+=C(nowceng,(tot-1)*300+i);
                pre[tot]%=MOD;
            }
        }
        int base = node[i].m/300;
        LL cnt = pre[base];
        int top = node[i].m%300;
        for(int i=0;i<top;i++){
            cnt=(cnt+C(nowceng,base*300+1+i))%MOD;
        }
        ans[node[i].id] = cnt  ;
    }
    for(int i=0;i<T;i++){
        printf("%lld\n",ans[i]);
    }
    return 0;
}

官方代码:

#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) fac[i] = 1ll * fac[i - 1] * i % MOD;
    inv[mx] = powi(fac[mx], MOD - 2); for (int i = mx - 1; ~i; -- i) 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;
            while (ik < lst[i][j].k) val = (val + C(in, ++ ik)) % MOD;
            while (ik > lst[i][j].k) val = (val + MOD - C(in, ik --)) % MOD;
            res[lst[i][j].i] = val;
        }
    }
    for (int i = 1; i <= T; ++ i) printf("%d\n", res[i]);
}

猜你喜欢

转载自blog.csdn.net/qq_37748451/article/details/81348199