Problem A: Colorful Balls

Description

Snuke放了N个一排彩色的球.从左起第i个球的颜色是ci重量是wi
她可以通过执行两种操作对这些球重新排序
操作1:选择两个相同颜色的球,假如他们的重量和小于等于X,交换两个球的位置
操作2:选择两个不同颜色的球,假如他们的重量和小于等于Y,交换两个球的位置
求我们总共可以得到多少种 不同的颜色序列?对答案取109+7的模

Input

N X Y
c1 w1
.
.
.
cN wN

Output

输出答案。

Sample Input

  1. sample input 1:
  2. 4 7 3
  3. 3 2
  4. 4 3
  5. 2 1
  6. 4 4
  7. sample input 2:
  8. 1 1 1
  9. 1 1
  10. sample input 3:
  11. 21 77 68
  12. 16 73
  13. 16 99
  14. 19 66
  15. 2 87
  16. 2 16
  17. 7 17
  18. 10 36
  19. 10 68
  20. 2 38
  21. 10 74
  22. 13 55
  23. 21 21
  24. 3 7
  25. 12 41
  26. 13 88
  27. 18 6
  28. 2 12
  29. 13 87
  30. 1 9
  31. 2 27
  32. 13 15

Sample Output

  1. sample output 1:
  2. 2
  3. sample output 2:
  4. 1
  5. sample output 3:
  6. 129729600

HINT

1≤N≤2×105

1≤X,Y≤109
1≤ci≤N
1≤wi≤109

分析

首先,如果球A可以和球B交换,球B也可以和球C交换,那么肯定可以通过球B将球A与球C交换。

所以只需要将可以交换的任意两个球之间连一条边,找出每个联通块中每种球颜色的个数,因为每个联通块内无论怎么排都行,所以就能用组合数求出当前那个联通块中合法排列的方案数,最后再将所有的联通块的方案数乘起来就能得到答案了。

但这种方法的时间复杂度是O(n2)的。

但我们可以设:

球a是全部球中重量最小的球。

球b是全部球中与球a不同色且重量最小的球。

若找不出球b,则只有一种颜色的球,故只有1种方案

若球a与球b不在同一个联通块内,则不可能出现两种不同颜色的球在同一个联通块内,故只有1种方案

而对于每一个球来说,如果它既不能连到球a,也不能连到球b,那么它不可能再连到其他异色的球。

所以只可能有1个联通块对答案做出贡献。

所以我们只需要求出所有可以连到球a或球b或连到一个与它同色且能连到球a或球b的球即可。

时间复杂度为O(n)

O(n)的时间求组合数详见欧拉定理

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. using namespace std;
  5. struct data{
  6. long long x,y;
  7. }t[];
  8. long long n,s1,s2,k1,k2,f[],k[],m=,s[],cnt,id[],sum,ans=,col[],colmax[];
  9. bool d[],r[];
  10. bool cmp(data a,data b){
  11. return a.y<b.y;
  12. }
  13. long long get_pow(long long a,long long b){
  14. long long p=;
  15. while(b){
  16. if(b%)p=(p*a)%m;
  17. a=(a*a)%m;
  18. b=b/;
  19. }
  20. return p;
  21. }
  22. long long c(long long a,long long b){
  23. return (((k[a]*f[b])%m)*f[a-b])%m;
  24. }
  25. void add(long long a){
  26. long long p=a;
  27. while(t[col[p]].y+t[a].y<=s1){
  28. if(!col[p])break;
  29. s[t[a].x]++;
  30. sum++;
  31. p=col[p];
  32. r[p]=;
  33. }
  34. }
  35. int main(){
  36. scanf("%lld%lld%lld",&n,&s1,&s2);
  37. k[]=;
  38. for(long long i=;i<=n;i++)k[i]=(k[i-]*i)%m;
  39. f[n]=get_pow(k[n],m-);
  40. for(long long i=n-;i>;i--)f[i]=(f[i+]*(i+))%m;
  41. f[]=;
  42. f[]=;
  43. for(long long i=;i<=n;i++)scanf("%lld%lld",&t[i].x,&t[i].y);
  44. sort(t+,t+n+,cmp);
  45. for(long long i=;i<=n;i++){
  46. col[colmax[t[i].x]]=i;
  47. colmax[t[i].x]=i;
  48. }
  49. k1=;
  50. k2=;
  51. while(k2<=n&&t[k2].x==t[k1].x)k2++;
  52. if(k2!=n+){
  53. if(t[k1].y+t[k2].y<=s2){
  54. for(long long i=;i<=n;i++){
  55. if((t[i].x!=t[k1].x&&t[k1].y+t[i].y<=s2)||(t[i].x!=t[k2].x&&t[k2].y+t[i].y<=s2)){
  56. if(!d[t[i].x]){
  57. d[t[i].x]=;
  58. r[i]=;
  59. cnt++;
  60. id[cnt]=t[i].x;
  61. s[t[i].x]++;
  62. sum++;
  63. add(i);
  64. }else if(!r[i]){
  65. s[t[i].x]++;
  66. r[i]=;
  67. sum++;
  68. }
  69. }
  70. }
  71. for(long long i=;i<=cnt;i++){
  72. ans=(ans*c(sum,s[id[i]]))%m;
  73. sum=sum-s[id[i]];
  74. }
  75. }
  76. }
  77. printf("%lld\n",ans);
  78. }

  

noip2019集训测试赛(二十一)Problem A: Colorful Balls的更多相关文章

  1. noip2019集训测试赛(二十一)Problem B: 红蓝树

    noip2019集训测试赛(二十一)Problem B: 红蓝树 Description 有一棵N个点,顶点标号为1到N的树.N−1条边中的第i条边连接顶点ai和bi.每条边在初始时被染成蓝色.高桥君 ...

  2. noip2017集训测试赛(十一)Problem C: 循环移位

    题面 Description 给定一个字符串 ss .现在问你有多少个本质不同的 ss 的子串 t=t1t2⋯tm(m>0)t=t1t2⋯tm(m>0) 使得将 tt 循环左移一位后变成的 ...

  3. 2016北京集训测试赛(十一)Problem C: 树链问题

    Solution 智障暴力题, 每个点维护一下子树信息, 树剖就好了. 我居然还傻了写了一发毛毛虫... #include <cstdio> #include <cctype> ...

  4. 题解和总结——noip2019集训测试赛(一)贪吃蛇+字符串+都城

    Problem A: 贪吃蛇 描述 Input Output Sample Input [样例输入1] 4 5 ##... ..1#@ 432#. ...#. [样例输出1] 4 [样例输入2] 4 ...

  5. 2016集训测试赛(二十一)Problem C: 虫子

    题目大意 给你一棵树, 每个点有一个点权. 有两种操作: link / cut 修改某个点的点权 每次操作后, 你要输出以下答案: 在整棵树中任意选两个点, 这两个点的LCA的期望权值. Soluti ...

  6. 2016集训测试赛(二十六)Problem A: bar

    Solution 首先审清题意, 这里要求的是子串而不是子序列... 我们考虑用1表示p, -1表示j. 用sum[i]表示字符串前\(i\)的前缀和. 则我们考虑一个字符串\([L, R]\)有什么 ...

  7. 2016集训测试赛(二十四)Problem B: Prz

    Solution 这道题有两个关键点: 如何找到以原串某一个位置为结尾的某个子序列的最晚出现位置 如何找到原串中某个位置之前的所有数字的最晚出现位置中的最大值 第一个关键点: 我们注意到每个数字在\( ...

  8. 2016集训测试赛(二十四)Problem C: 棋盘控制

    Solution 场上的想法(显然是错的)是这样的: 我们假设棋子是一个一个地放置的, 考虑在放置棋子的过程中可能出现哪些状态. 我们令有序整数对\((i, j)\)表示总共控制了\(i\)行\(j\ ...

  9. 2016集训测试赛(二十)Problem B: 字典树

    题目大意 你们自己感受一下原题的画风... 我怀疑出题人当年就是语文爆零的 下面复述一下出题人的意思: 操作1: 给你一个点集, 要你在trie上找到所有这样的点, 满足点集中存在某个点所表示的字符串 ...

随机推荐

  1. (4)ardunio 矩阵求解官方库改造,添加逆的求解

    多此一举,原来官方库给了求逆的函数,在源码里 除此之外,还有转置矩阵,只不过样例没显示出来. //Matrix Inversion Routine // * This function inverts ...

  2. [ARIA] Create an Accessible Tooltip on a Text Input

    Here we use HTML and CSS to create a stylish yet semantic tooltip on a form input. I am using aria-d ...

  3. chef test-kitchen Could not load the 'vagrant' driver from the load path 问题解决

    今天使用chef 的kitchen,运行kitchen list 发现了如下错误: >>>>>> ------Exception------- >>&g ...

  4. Python 03 pip 的安装和使用

    原文:https://www.runoob.com/w3cnote/python-pip-install-usage.html 原文:https://www.jianshu.com/p/2be68ef ...

  5. Linux 系统管理——磁盘管理及文件系统实例

    1.为主机新增两块30GB的SCSI硬盘 2.划分3个主分区,各5GB,剩余空间作为扩展分区 3.在扩展分区中建立2个逻辑分区,容量分别为2GB.10GB 4.将第一个逻辑分区的类型改为swap 5. ...

  6. P4899 【[IOI2018] werewolf 狼人】

    感觉已经几次碰到这种类型的题目了,写篇\(Blog\)总结一下 题意: 是否存在一条\((s_i, t_i)\)的路径,满足先只走编号不超过\(L_i\)的点,再走编号不超过\(R_i\)的点 \(S ...

  7. linux命令之------More命令

    More命令 1)作用:命令类似cat,不过会以一页一页的形式显示,更方便使用者逐页阅读. 2)-num:一次显示的行数 3)-d:提示使用者,在画面下方显示[Press space to conti ...

  8. 2016android在线测试15-图像 camera2

    1.ImageView类用于显示各种图像,例如:图标,图片,下面对于ImageView类加载图片方法的描述有: void setImageResource(int resld): 设置Drawanbl ...

  9. Android程序员问答题

    前言 最近三个月内,不断地进行移动应用开发在线测试题,也积累了不一样的知识.这也将对android studio有很好的掌握,对将来面试也很有好处.那么我就分享给大家.分享是一种幸福,这是一种质的飞越 ...

  10. 缺陷的优先程度(Priority)

    测试人员希望程序员什么时间哪个版本修改该bug (1)Urgent 立即修改否则影响开发进度 (2)Veryhigh 本版本修改 (3)High 下个版本修改 (4)Medium 发布前修改 (5)L ...