该浏览器不支持canvas

HDU6333-2018ACM暑假多校联合训练1002-Harvest of Apples-莫队+费马小定理

题意很简单啦,求S(n,m)的值

通过打表我们可以知道

S(n + 1, m) = S(n, m) * 2 - C(n, m);

S(n - 1, m) = (S(n, m) + C(n - 1, m)) / 2;

首先我们考虑杨辉三角和二项式定理,但是看了看数据情况,貌似时间不允许呢

这个时候就要祭出莫队算法啦,关于莫队算法呢,更详细的理解请看:2010国家集训队《小Z的袜子》命题报告

莫队算法是一种用于解决可离线的,求区间[L,R]问题的算法

这个题当然就可以离线去求啦,莫队算法在解决离线区间询问几乎是无敌的(分块大法好),复杂度在O(n^3/2)左右

那这个题也妥妥的稳过了

 

这个题由于在处理阶乘的时候会出现被取余的情况,所以在计算C(L,R)进行除运算阶乘时,计算会不正确,这时候就需要用到费马小定理去计算逆元啦

费马小定理:假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

Problem B. Harvest of Apples

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3313    Accepted Submission(s): 1284


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 (1T105) denoting the number of test cases.
Each test case consists of one line with two integers n,m (1mn105).
 


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

 

 

#include <iostream>
#include <cmath>
#include <algorithm>

using namespace std;

const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
const int MAX = 1e5;
int pos[maxn];
long long ans[maxn];
long long jx[maxn];
long long jxny[maxn];

struct node
{
    int l, r;
    int id;
    bool operator < (node a) const
    {
        if (pos[id] == pos[a.id])
            return r < a.r;
        return pos[id] < pos[a.id];
    }
}q[maxn];

long long quick_mod(long long n, long long m)
{
    long long ret = 1;
    while (m>0) {
        if (m & 1) ret = ret * n%mod;
        n = n * n%mod;
        m >>= 1;
    }
    return ret;
}//快速幂

void init() {
    jx[0] = 1;
    for (int i = 1; i <= MAX; i++) {
        jx[i] = (jx[i - 1] * i) % mod;
    }
    jxny[MAX] = quick_mod(jx[MAX], mod - 2);
    for (int i = MAX - 1; i >= 0; i--) {
        jxny[i] = jxny[i + 1] * (i + 1) % mod;
    }
}//预处理阶乘和逆元

long long get(int l, int r)
{
    if (r > l)
        return 0;
    return jx[l] * jxny[r] % mod * jxny[l - r] % mod;
}

int main()
{
    init();
    ios::sync_with_stdio(false);
    int t;
    cin >> t;
    int sq = sqrt(10000);
    for (int i = 0; i < t; i++)
    {
        cin >> q[i].l >> q[i].r;
        q[i].id = i;
        pos[i] = q[i].l / sq;
    }

    sort(q,q+t);

    int l = 1, r = 0;
    long long num = 1;
    for (int i = 0; i < t; i++)
    {
        while (l < q[i].l)
        {
            num = (num * 2 + mod - get(l,r)) % mod;
            l++;
        }
        while (l > q[i].l)
        {
            l--;
            num = (num + get(l, r)) * quick_mod(2, mod - 2) % mod;
        }
        while (r < q[i].r)
        {
            r++;
            num = (num + get(l, r) + mod) % mod;
        }
        while (r > q[i].r)
        {
            num = (num - get(l, r) + mod) % mod;
            r--;
        }
        ans[q[i].id] = num;
    }

    for (int i = 0; i < t; i++)
        cout << ans[i] << endl;

    return 0;
}

 

 

 

posted @ 2018-08-17 16:39  真是啰嗦  阅读(321)  评论(0)    收藏  举报