题意大致是有n个苹果,问你最多拿走m个苹果有多少种拿法。题目非常简单,就是求C(n,0)+...+C(n,m)的组合数的和,但是询问足足有1e5个,然后n,m都是1e5的范围,直接暴力的话肯定时间炸到奶奶都不认识了。当时想了好多好多,各种骚操作都想了一遍就是没想到居然是莫队....我用S(n,m)来记录C(n,0)+...+C(n,m)的和作为一个询问的答案

由组合数公式C(n,m) = C(n-1,m-1)+C(n-1,m)可以推的下面的式子

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

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

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

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

这样发现居然是一个莫队的基本操作....然而只知道这几点也是不够的,因为组合数计算涉及到除法,所以得求逆元,还是阶乘的逆元,所以得先预处理出1~n的阶乘和它们的逆元,求逆元也是很耗时间的,但是我们可以通过递推一遍把阶乘的逆元求出来

设f(x)为x的逆元
那么 f(n!) = f( (n-)!*n ) = f((n-)!)*f(n);
将f(n)除过来 f(n!)*f(f(n)) = f((n-)!)
因为x的逆元的逆元就是x本身, 因此得到公式f(n!)*n = f((n-1)!),这样我们只要求出最大的阶乘的逆元就可以从大到小推出所有逆元的值

就酱(顺便说一句不知道为啥hdu选c++会TLE或者WA,得用G++编译)

 #include <iostream>
#include <string.h>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <math.h>
#include <string>
#include <algorithm>
#include <functional> #define SIGMA_SIZE 26
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x&-x)
#define foe(i, a, b) for(int i=a; i<=b; i++)
#define fo(i, a, b) for(int i=a; i<b; i++)
#define pii pair<int,int>
#pragma warning ( disable : 4996 ) using namespace std;
typedef long long LL;
inline double dMax(double a, double b) { return a>b ? a : b; }
inline double dMin(double a, double b) { return a>b ? b : a; }
inline LL LMax(LL a, LL b) { return a>b ? a : b; }
inline LL LMin(LL a, LL b) { return a>b ? b : a; }
inline LL lgcd(LL a, LL b) { return b == ? a : lgcd(b, a%b); }
inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; } //a*b = gcd*lcm
inline int Max(int a, int b) { return a>b ? a : b; }
inline int Min(int a, int b) { return a>b ? b : a; }
inline int gcd(int a, int b) { return b == ? a : gcd(b, a%b); }
inline int lcm(int a, int b) { return a / gcd(a, b)*b; } //a*b = gcd*lcm
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = 1e9+;
const double eps = 1e-;
const int inf = 0x3f3f3f3f;
const int maxk = 3e6 + ;
const int maxn = 1e5+; int n, m, unit;
int belong[maxn];
LL fac[maxn], inv[maxn],invof2;
LL ans[maxn];
struct node {
int lhs, rhs, id;
}pp[maxn]; bool cmp(const node& a, const node& b)
{
if (belong[a.lhs] == belong[b.lhs])
return (belong[a.lhs]&) ? a.rhs<b.rhs : a.rhs>b.rhs;
return a.lhs < b.lhs;
} //设f(x)为x的逆元
//f(n!) = f( (n-1)!*n ) = f((n-1)!)*f(n);
//将f(n)除过来 f(n!)*f(f(n)) = f((n-1)!)
//因此可以从最大的n反向推回小的
LL getM( LL a, LL b, LL m)
{
LL ans = , base = a;
while (b)
{
if ( b & )
ans = (ans*base) % m;
base = (base*base) % m;
b >>= ;
}
return ans;
} void init()
{
fac[] = fac[] = ;
inv[] = inv[] = ;
foe(i, , maxn)
fac[i] = fac[i-]*i%mod; inv[maxn-] = getM(fac[maxn-], mod-, mod);
invof2 = getM(, mod-, mod);
for ( int i = maxn-; i >= ; i-- )
inv[i] = (inv[i+]*(i+))%mod;
} LL C(int down, int up)
{
if ( up > down ) return ;
return fac[down]*inv[up]%mod*inv[down-up]%mod;
} int main()
{
init();
int T;
cin >> T;
unit = sqrt(T); foe(i, , T)
{
scanf("%d %d", &n, &m);
pp[i].lhs = n; pp[i].rhs = m;
pp[i].id = i;
belong[i] = i/unit+;
}
sort(pp+, pp++T, cmp); //(l代表n, r代表m)
int l = , r = ;
LL sum = ; for ( int i = ; i <= T; i++ )
{
while (r < pp[i].rhs) {
r++;
sum = (sum + C(l, r))%mod;
} while (r > pp[i].rhs) {
sum = (sum - C(l, r)+mod)%mod;
r--;
} while (l < pp[i].lhs) {
sum = ((LL)*sum - C(l, r)+mod)%mod;
l++;
} while (l > pp[i].lhs) {
l--;
sum = (sum+C(l,r))%mod*invof2%mod;
} ans[pp[i].id] = sum;
} foe(i, , T)
printf("%lld\n", ans[i]);
return ;
}

Harvest of Apples (HDU多校第四场 B) (HDU 6333 ) 莫队 + 组合数 + 逆元的更多相关文章

  1. 2018 HDU多校第四场赛后补题

    2018 HDU多校第四场赛后补题 自己学校出的毒瘤场..吃枣药丸 hdu中的题号是6332 - 6343. K. Expression in Memories 题意: 判断一个简化版的算术表达式是否 ...

  2. HDU 多校第四场题解

    对于 D 题的原题意,出题人和验题人赛前都没有发现标算存在的问题,导致了许多选手的疑惑和时间的浪费,在此表示真诚的歉意! 预计难度分布: Easy - DJKL, Medium - ABCEG, Ha ...

  3. HDU 6333 莫队+组合数

    Problem B. Harvest of Apples Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K ...

  4. 2014多校第四场1006 || HDU 4902 Nice boat (线段树 区间更新)

    题目链接 题意 : 给你n个初值,然后进行两种操作,第一种操作是将(L,R)这一区间上所有的数变成x,第二种操作是将(L,R)这一区间上所有大于x的数a[i]变成gcd(x,a[i]).输出最后n个数 ...

  5. 2014多校第四场1005 || HDU 4901 The Romantic Hero (DP)

    题目链接 题意 :给你一个数列,让你从中挑选一些数组成集合S,挑另外一些数组成集合T,要求是S中的每一个数在原序列中的下标要小于T中每一个数在原序列中下标.S中所有数按位异或后的值要与T中所有的数按位 ...

  6. hdu多校第四场 1003 (hdu6616) Divide the Stones 机智题

    题意: 给你重量分别为1到n的n个石头,让你分成重量相等,数量也相等的k组,保证k是n的约数.问你能不能分配,如果能,输出具体的分配方案. 题解: 首先,如果1到n之和不能整除k,那么一定不能如题意分 ...

  7. hdu多校第四场 1007 (hdu6620) Just an Old Puzzle 逆序对

    题意: 给你一个数字拼图,问你数字拼图能否能复原成原来的样子. 题解: 数字拼图的性质是,逆序数奇偶相同时,可以互相转化,逆序数奇偶不同,不能互相转化. 因此统计逆序对即可. #include< ...

  8. hdu多校第四场1001 (hdu6614) AND Minimum Spanning Tree 签到

    题意: 一个完全图,某两点边权为这两点编号之按位与,求最小生成树,输出字典序最小的. 题解: 如果点数不为$2^n-1$,则每一点均可找到一点,两点之间边权为0,只需找到该点二进制下其最左边的0是第几 ...

  9. 2018 HDU多校第三场赛后补题

    2018 HDU多校第三场赛后补题 从易到难来写吧,其中题意有些直接摘了Claris的,数据范围是就不标了. 如果需要可以去hdu题库里找.题号是6319 - 6331. L. Visual Cube ...

随机推荐

  1. openwrt xfrp移植

    对开源软件表示支持 https://github.com/KunTengRom/xfrp 上传编译,选择 cp .config xxx make 刷机 客户端配置文件: /tmp/etc# cat x ...

  2. 校园商铺-4店铺注册功能模块-4Dto之ShopExecution的实现

    1. DTO:添加店铺的返回类型 问题:为什么不直接用实体类Shop呢? 原因:在操作Shop的时候,必然会有一个状态.添加店铺,添加成功,还是添加失败? 如果添加失败,失败是一个什么状态,这些都是要 ...

  3. 廖雪峰Java16函数式编程-2Stream-5filter

    1.filter简介 Stream.filter()是一个转换方法,把一个Stream转换为另一个Stream. 所谓filter操作,就是对一个Stream的所有元素进行测试,不满足条件的元素就被过 ...

  4. cocos2D-X LUA 非常简单的一个贪吃蛇案例

    --[[ 贪吃蛇 ]] local RetroSnaker = class("RetroSnaker", function() return cc.Layer:create(); ...

  5. JLOI 2013 卡牌游戏 bzoj3191

    题目描述 N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张卡片,假设卡片上的数字为X,则庄家首先把 ...

  6. 将maven项目打成war包

    //修改成war包 <packaging>war</packaging> //plugins中添加新的配置 <build> <plugins> < ...

  7. Docker系列(九):Kubernetes架构深度解析

    Kubernetes重要概念 Docker解决了打包和隔离的问题,但我们需要更多:调度的问题,生命周期及健康状况,服务发现,监控,认证,容器聚合. Kubernetes概述 开源DOcker容器编排系 ...

  8. substring常用的两种方法

    1.public String substring(int beginIndex, int endIndex) 第一个参数int为开始的索引,对应String数字中的开始位置, 第二个参数是截止的索引 ...

  9. vue 计算属性实现过滤关键词

    效果 html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <m ...

  10. Oracle如何用单字段或多字段进行查重

    最近在整理数据形成信用报告,发现重复的数据真的多,梳理都好久.我就做个笔记把去掉重复数据的方法整理下来.方便我后期查阅. 我将我目前已知的两种去重方法分为:视图去重和表去重.原理就是有无rowid这个 ...