HDU - 6333 Harvest of Apples 分块暴力查询 莫队

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lifelikes/article/details/81347607

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
2
5 2
1000 500

Sample Output
16
924129523

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

解题思路:
比赛时想出了解法,但写了两个小时,比赛时没交上去。。。 难受。
T,n,m为 1e5
总状态数高达1e10 显然不能暴力枚举
又因为T为1e5。 思考是否可以通过提高询问复杂度来降低枚举状态的复杂度。
考虑 , n为定值的情况。
我们可以取一些定点,然后每次查询就通过离要查询状态最近的点出发。暴力的更新到所需要的状态。
假设我们去根号m个定点 , 那么每次查询复杂度就降低到了根号n
所以如果状态能够线性处理出来的话,这个问题就很好解决了。
考虑离线处理。
按照以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) 自己在草稿纸上算一算就很容易能求出来了
这样 状态的转移也可以线性的完成了。
总复杂度就控制在了O(n^(3/2)) n为1e5 时限给了两秒 可以接受。
不过有一些细节需要考虑一下。 这里就不讲了,简直耻辱。。。。

用莫队写就简单很多。一样是对m分块 下面放出比赛时写的分块代码 和莫队代码(同学写的 不想在写这题了)

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <bitset>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
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;
        //cout<<pre[i]<<endl;
    }
}
LL ans[MAX];
int main(){
    int T;
    init();
//    int a,b;
//    while(cin>>a>>b){
//        cout<<C(a,b)%MOD<<endl;
//    }
//    freopen("b.in","r",stdin);
//    freopen("b.out","w",stdout);
    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++){
           //cout<<cnt<<endl;
            cnt=(cnt+C(nowceng,base*300+1+i))%MOD;
            //cout<<C(nowceng,base*300+1+i)<<endl;
           // cout<<cnt<<endl;
        }
        ans[node[i].id] = cnt  ;
    }
    for(int i=0;i<T;i++){
        printf("%lld\n",ans[i]);
        //cout<<quickpow(2,node[i].n)<<endl;
    }
}
#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=b;i>=a;i--)
#define FIN freopen("in.txt","r",stdin)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
using namespace std;
const int MX=1e5+7;
const int mod=1e9+7;

struct Query{
    int n,m,id;
}que[MX];
int pos[MX];
ll inv[MX],f[MX],ans[MX];
bool cmp(Query A,Query B){
    if(pos[A.n]!=pos[B.n]) return A.n<B.n;
    return A.m<B.m;
}

ll qpow(ll a,ll b){ll res=1;while(b){if(b&1) res=(res*a)%mod;a=(a*a)%mod;b>>=1;}return res;}
void init(){
    f[1]=1;
    for(int i=2;i<MX;i++) f[i]=(f[i-1]*i)%mod;
    for(int i=1;i<MX;i++) inv[i]=qpow(f[i],mod-2);
}
ll C(int n,int m){
    if(n < 0 || m < 0 || m > n) return 0;
    if(m == 0 || m == n) return 1;
    return f[n]*inv[n-m]%mod*inv[m]%mod;
}
ll res=1;

int main(){
    init();
    int T;scanf("%d",&T);
    int block=(int)sqrt(MX);
    rep(i,1,MX-1) pos[i]=(i-1)/block;
    rep(i,1,T){
        scanf("%d%d",&que[i].n,&que[i].m);
        que[i].id=i;
    }
    sort(que+1,que+T+1,cmp);
    int N=1,M=0;
    rep(i,1,T){
        while(N<que[i].n){
            res=(2*res-C(N++,M)+mod)%mod;
        }
        while(N>que[i].n){
            res=((res+C(--N,M))*inv[2])%mod;
        }
        while(M<que[i].m){
            res=(res+C(N,++M))%mod;
        }
        while(M>que[i].m){
            res=(res-C(N,M--)+mod)%mod;
        }
        ans[que[i].id]=res;
    }
    rep(i,1,T)
        printf("%lld\n", ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lifelikes/article/details/81347607
今日推荐