题目传送门:https://agc012.contest.atcoder.jp/tasks/agc012_d

题目翻译

给你一排一共\(N\)个球,每个球有一个颜色\(c_i\)和一个重量\(w_i\),如果两个球颜色相同,重量相加不超过\(x\)那我就可以交换这俩个球的位置。如果两个球颜色不同,重量相加不超过\(y\)那我也可以交换这俩球的位置。你可以随心所欲的交换或者不交换,求最后颜色序列的种数。\(N\leqslant 2×10^5;c_i\leqslant N;w_i,x,y\leqslant10^9\)

题解

首先,如果\(a,b\)可以交换,\(b,c\)可以交换,那么\(a,c\)也可以直接交换。

对于颜色相同,我们把每个可以和当前颜色重量最小的球交换位置的球和当前颜色重量最小的球连一条边。那么对于可以以最小值为媒介交换的球也在一个联通块内了。

对于颜色不同,假设当前球和重量最小的球也颜色不同,那就把当前球和重量最小的那个球连一条边,否则就把当前球与跟重量最小的球颜色不同的球当中重量最小的球连边。如果不存在这个球,那就不连。

然后答案就是:

\[\sum\limits_{i=1}^{m}\frac{cnt_i!}{\prod\limits_{j=1}^{n}sum_j!}
\]

\(m\)是联通块个数,\(cnt_i\)表示第\(i\)个联通块大小,\(sum_j\)表示在第\(i\)个联通块中颜色为\(j\)的球有多少个。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std; const int maxn=2e5+5,pps=1e9+7; bool vis[maxn];
int n,x,y,tot,ans=1,top;
int fac[maxn],inv[maxn],sta[maxn],insta[maxn];
int sum[maxn],now[maxn],pre[maxn<<2],son[maxn<<2],color[maxn]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} struct Ball {
int c,w,id;
}b[maxn]; int quick(int a,int b) {
int sum=1;
while(b) {
if(b&1)sum=1ll*sum*a%pps;
a=1ll*a*a%pps,b>>=1;
}
return sum;
} bool cmp1(Ball a,Ball b) {
if(a.c==b.c)return a.w<b.w;
return a.c<b.c;
} bool cmp2(Ball a,Ball b) {
if(a.w==b.w)return a.c<b.c;
return a.w<b.w;
} void add(int a,int b) {
pre[++tot]=now[a];
now[a]=tot,son[tot]=b;
} void work1() {
int lst=0;
for(int i=1;i<=n;i++) {
if(b[i].c!=b[lst].c) {
lst=i;continue;
}
if(b[i].w+b[lst].w<=x) {
add(b[i].id,b[lst].id);
add(b[lst].id,b[i].id);
}
}
} void work2() {
int fake;b[n+1].w=1e9;
for(fake=2;fake<=n;fake++)
if(b[fake].c!=b[1].c)break;
for(int i=2;i<=n;i++)
if(b[i].c!=b[1].c) {
if(b[i].w+b[1].w>y)break;
add(b[i].id,b[1].id);
add(b[1].id,b[i].id);
}
else if(b[i].w+b[fake].w<=y) {
add(b[i].id,b[fake].id);
add(b[fake].id,b[i].id);
}
} void prepare() {
fac[0]=inv[0]=1;
for(int i=1;i<=n;i++)
fac[i]=1ll*fac[i-1]*i%pps;
inv[n]=quick(fac[n],pps-2);
for(int i=n-1;i;i--)
inv[i]=1ll*inv[i+1]*(i+1)%pps;
} void dfs(int u) {
vis[u]=1;
int c=color[u];
if(!insta[c]) {
sta[++top]=c;
insta[c]=top;
sum[top]=1;
}
else sum[insta[c]]++;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v])dfs(v);
} void calc() {
int cnt=0;
while(top) {
ans=1ll*ans*inv[sum[top]]%pps;
cnt+=sum[top],insta[sta[top]]=0,sta[top]=0,sum[top]=0,top--;
}
ans=1ll*ans*fac[cnt]%pps;
} int main() {
n=read(),x=read(),y=read(),prepare();
for(int i=1;i<=n;i++)
color[i]=b[i].c=read(),b[i].w=read(),b[i].id=i;
sort(b+1,b+n+1,cmp1);work1();
sort(b+1,b+n+1,cmp2);work2();
for(int i=1;i<=n;i++)
if(!vis[i])dfs(i),calc();
printf("%d\n",ans);
return 0;
}

AtCoder Grand Contest 012 D:Colorful Balls的更多相关文章

  1. AtCoder Grand Contest 012 C:Tautonym Puzzle

    题目传送门:https://agc012.contest.atcoder.jp/tasks/agc012_c 题目翻译 如果一个字符串是好的,那么这个字符串的前半部分和后半部分肯定一模一样.比如\(a ...

  2. AtCoder Grand Contest 012

    AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...

  3. AtCoder Grand Contest 012 A

    A - AtCoder Group Contest Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statem ...

  4. AtCoder Grand Contest 012 A - AtCoder Group Contest(贪心)

    Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statement There are 3N participa ...

  5. AtCoder Grand Contest 012 D Colorful Balls

    题意: 有N个球排成一行,第i个球颜色为ci, 权为wi, 如果两个同色球权值和 <= X 则它们可以交换: 如果两个异色球权值和 <= Y 则它们可以交换:不限制交换次数,求能到达的颜色 ...

  6. AtCoder Grand Contest 009 D:Uninity

    题目传送门:https://agc009.contest.atcoder.jp/tasks/agc009_d 题目翻译 定义只有一个点的树权值为\(0\),若干棵(可以是\(0\)棵)权值为\(k\) ...

  7. AtCoder Grand Contest 009 E:Eternal Average

    题目传送门:https://agc009.contest.atcoder.jp/tasks/agc009_e 题目翻译 纸上写了\(N\)个\(1\)和\(M\)个\(0\),你每次可以选择\(k\) ...

  8. AtCoder Grand Contest 004 C:AND Grid

    题目传送门:https://agc004.contest.atcoder.jp/tasks/agc004_c 题目翻译 给你一张网格图,指定的格子是紫色的,要求你构造出两张网格图,其中一张你可以构造一 ...

  9. AtCoder Grand Contest 014 D:Black and White Tree

    题目传送门:https://agc014.contest.atcoder.jp/tasks/agc014_d 题目翻译 给你一棵树,每次任选一个点染色,先手染白色,后手染黑色.如果最后存在一个白色的点 ...

随机推荐

  1. Java中字符串转为16进制表示

    Java中字符串转为16进制表示 String str = "鲸"; char[] chars = "0123456789ABCDEF".toCharArray ...

  2. java性能监控工具jmc-windows

    jmc Java Mission Control is a Profiling, Monitoring, and Diagnostics Tools Suite. Synopsis jmc [ opt ...

  3. MRP routing设置释疑

    Jeffer9@gmail.com         工艺是指在不同工作中心执行的作业序列         作业的详细信息 Number of cycles 在该工作中心操作几个循环 Number of ...

  4. binary-tree-maximum-path-sum——二叉树任意一条路径上的最大值

    Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree. ...

  5. Solaris分布式文件系统NFS

    NFS存在的意思是让不同unix系统之间可以传输数据.这样可以合理的利用资源.   对每一个系统,建立一个NFS文件系统,进行数据的备份. NFS守护进程: nfsd mountd locked st ...

  6. Windows下编程2----- C语言常用函数举例

    几个小函数 1.    //MessageBoxA(0,"网络故障,重新登录","qq error",3); //弹出对话框 2.    //ShellExec ...

  7. Python+Selenium框架unittest执行脚本方法之discover()方法

    继续接着介绍,如何利用unittest管理和执行测试用例的问题,这里我们还是利用之前已经有的三条测试用例,如果你跳过了前面文章,请回到框架设计篇的第八篇和第七篇,里面有相关测试类的文件.本文来介绍,如 ...

  8. JavaScript 日期格式化 简单有用

    JavaScript 日期格式化 简单有用 代码例如以下,引入jquery后直接后增加下面代码刷新可測试 Date.prototype.Format = function (fmt) { //auth ...

  9. C# 知识点随手学习网站推荐

    http://www.studyofnet.com/news/list-8881.2-1-1.html

  10. lowB三人组代码示例

    冒泡排序:列表在内存重只存一份,所以不需要重复赋值 import random from timewrap import * #时间装饰器 # 初级版本 @cal_time def bubble_so ...