莫队 + 组合 + 逆元 HDU 5145
来源:互联网 发布:最短路径算法floyd实例 编辑:程序博客网 时间:2024/06/06 13:58
NPY and girls
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1436 Accepted Submission(s): 491
Here comes the problem,(NPY doesn't want to learn how to use excavator),he wonders how many different ways there can be in which he can visit his girls.The different ways are different means he visits these classrooms in different order.
For each test case,there are two integers
The following single line contains N integers,
The following m lines,each line contains two integers
24 21 2 1 31 31 41 111 1
3121
比如 : 三个女孩 1 1 2 询问 [1,3] 那么就有 1 1 2 , 1 2 1, 2 1 1 三种情况
思路:
我们继续根据上面的那个例子来找规律。 当有三个女生 1 1 2 的时候答案是3
那么加多一个 2 的女生的时候会是什么情况呢? _1_1_2_ 我们可以看到,新来的女生可以在这四个位置中挑一个坐
那么原来有 3 种,现在有 4种坐法,所以就有 3 * 4 = 12 种情况了,但是我们会发现 _1_1_22 和 _1_122_ 这两种是一样的,答案应该是 6种 其实就是四个空位来分给 两个 1 和两个 2 ans2 = C[4][2] * C[4 - 2][2]
那么原来 1 1 2 的时候是 ans1 = C[3][2] * C[3 - 2][1]
这两者之间的关系就是 ans2 = ans1 * 4 / 2 也就是 C[3][2] * C[3 - 2][1] * (3 + 1) / (1 + 1) = C[4][2]
他的实际含义就是 有 4 个空位可以插入,但是有 2 个 2,所以有 重复的 所以应该是 * 4 / 2
那么同理 1 1 1 2 的情况由 1 1 2 得来就是 = 3 * 4 / 3 = 4
所以 对于新增加一个值x 则 flag[x]++ Ans = Ans * (r - l + 1) / (flag[x])
对于减的就相反操作 Ans = Ans * flag[x] / (r - 1 + 1) flag[x]--
做除法的时候没法取模,所以要用逆元 inv[] 去做除法 所以 Ans / (flag[x]) = Ans * inv[flag[x]]
需要注意的是 不能写成 dele(a[l++]) 而要写成 dele(a[l]) , l++ ,否则在上传了值之后 l 就变了的话,区间长度也变了,答案就会计算错误
#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>using namespace std;#define maxn 30030#define mem(a,x) memset(a,x,sizeof(a))#define ll long longconst ll mod = 1000000007;struct quse{int l,r,id,pos;}q[maxn];int n,m,a[maxn],flag[maxn];int l,r;ll Ans,ans[maxn];ll inv[maxn]; int cmp(quse a,quse b){if(a.pos != b.pos)return a.pos < b.pos;return a.r < b.r;}ll Pow(ll a,ll b){ll tmp = 1;while(b){if(b & 1){tmp *= a;tmp %= mod;}a *= a;a %= mod;b /= 2;}return tmp;}void init(){for(int i = 1;i <= 30000;i++)inv[i] = Pow(i,mod - 2);}void add(int x){flag[x]++;Ans = Ans * (r - l + 1) % mod;Ans = Ans * inv[flag[x]] % mod;}void dele(int x){Ans = Ans * flag[x] % mod;Ans = Ans * inv[r - l + 1] % mod;flag[x]--;}int main(){init(); int T;scanf("%d",&T);while(T--){scanf("%d %d",&n,&m);int block = sqrt(n);for(int i = 1;i <= n;i++)scanf("%d",&a[i]);for(int i = 1;i <= m;i++){scanf("%d %d",&q[i].l,&q[i].r);q[i].id = i;q[i].pos = q[i].l / block;}sort(q + 1,q + 1 + m,cmp);mem(ans,0);mem(flag,0);l = 1,r = 0;Ans = 1;for(int i = 1;i <= m;i++){while(q[i].r > r){add(a[++r]);}while(q[i].r < r){dele(a[r]);r--;}while(q[i].l > l){dele(a[l]);l++;}while(q[i].l < l){add(a[--l]);}ans[q[i].id] = Ans;}for(int i = 1;i <= m;i++)printf("%lld\n",ans[i]);}return 0;}/*210 31 2 3 1 2 1 3 2 1 51 102 94 6*/
- 莫队 + 组合 + 逆元 HDU 5145
- Hdu 5698 瞬间移动【组合+逆元】
- HDU 5651 xiaoxin juju needs help 逆元&组合数学
- HDU 5698 瞬间移动 (组合数 + 阶乘逆元)
- HDU 5698 瞬间移动 [数论] [逆元] [组合数取模]
- HDU 6044 Limited Permutation (组合数+逆元)
- HDU 5698 瞬间移动【组合数+逆元】
- HDU 6114 Chess【逆元+组合数】【模板题】
- fzu2015vote 组合 逆元
- fzu2020 组合,逆元
- 组合数、逆元,数学
- FZU2282-组合数-逆元
- 组合数取模之逆元
- HDU 3037 Saving Beans (组合+Lucas定理+逆元+快速幂)
- hdu 4869 Turn the pokers(递推&组合数学&逆元)
- hdu - 4869 - Turn the pokers(组合数学 + 乘法逆元)
- hdu 3037 求组合数(卢卡斯定理+乘法逆元)
- [HDU 5184][BestCoder #32]Brackets(卡特兰数+组合数学+乘法逆元)
- matlab2c使用c++实现matlab函数系列教程-sin函数
- Unity UGUI点击、拖动等事件
- matlab2c使用c++实现matlab函数系列教程-cos函数
- 《DevOps 实践》
- Codeforces 851B
- 莫队 + 组合 + 逆元 HDU 5145
- CAGradientlayer设置视图背景的渐变效果
- 基于ArcGIS的Python编程秘笈笔记(一):面向ArcGIS的Python语言基础
- Logstash安装配置
- Map集合的四种种遍历方式
- U盘无法复制进去东西,提示错误0x80071AC3 无法完成操作
- Django安装(windows)
- let和const命令
- codeforce 850A Five Dimensional Points(特殊判别)