zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 012 D:Colorful Balls

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

    题目翻译

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

    题解

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

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

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

    然后答案就是:

    [sumlimits_{i=1}^{m}frac{cnt_i!}{prodlimits_{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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    各种工具网站汇总
    Python中numpy库unique函数解析
    matlab中集合运算函数——解析
    hash算法搜索获得api函数地址的实现,"kernel32.dll", "CreateThread"
    PEB及LDR链
    PE文件结构及其加载机制
    spring boot2.0一看就会的超详细快速入门(七)-访问静态资源
    spring boot2.0一看就会的超详细快速入门(六)-集成Thymeleaf模板引擎
    spring boot2.0一看就会的超详细快速入门(五)-开发人员工具devtools
    spring boot2.0一看就会的超详细快速入门(四)-自动配置原理
  • 原文地址:https://www.cnblogs.com/AKMer/p/10036776.html
Copyright © 2011-2022 走看看