hdu6333 Problem B. Harvest of Apples

题意:一颗树上有n个苹果,求取不大于k个苹果的方案数。
输入:T个案例,输入n,m,n,m<=100000
输出:方案数mod 1000000007

做法:
这里写图片描述

方案数= mi=1C(i,n) ∑ i = 1 m C ( i , n ) ,直接暴力会T,做的时候一直在想数学公式和找规律,没想到用莫队。n,m可以看成r,l,还有区间迁移的时候不是简单的加减,要找到区间转移的变化方程式。

有一点要注意mod要用const定义,不然会T的。

#include"bits/stdc++.h"
using namespace std;
typedef long long ll;
#define N 200000
const int mod=1000000007;
const int MOD = 1000000007;
int fac[N], inv[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 n,m;

struct node{
    int n,m,id;
}q[100005];
int cmp(node a,node b){
    return a.n<b.n;
}
int ans[100005];
vector<node>lst[N];
int in_chunk[100004];
int main(){
    int 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;
    int chunk=sqrt(mx);
    int 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;
     //   cout<<cnt<<endl;
    }

    cnt--;
    int T;
    scanf("%d",&T);
    for (int i = 1; i <= T; ++ i)
    {
        scanf("%d%d", &q[i].n, &q[i].m), q[i].id = i;
        lst[in_chunk[q[i].m]].push_back(q[i]);
    }
    for(int i=1;i<=cnt;i++)
    if(lst[i].size())
    {
        sort(lst[i].begin(), lst[i].end(), cmp);
        int sum=0;
        int l=-1,r=lst[i][0].n;
        for(int j=0;j<lst[i].size();j++){
        while(r<lst[i][j].n)sum=(0ll+mod+sum+sum-C(r++,l))%mod;
        while(l<lst[i][j].m)sum=(sum+C(r,++l))%mod;
        while(l>lst[i][j].m)sum=(sum+mod-C(r,l--))%mod;
        ans[lst[i][j].id]=sum;
    }
    }
    for(int i=1;i<=T;i++){
        printf("%d\n",ans[i]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值