zoukankan      html  css  js  c++  java
  • IOI2021集训队作业277BK Tours

    给出一个无向图,你需要给每条边染(k)种色,使得:对于每个环,这(k)种色的出现次数相同。

    问有哪些合法的(k)

    (n,mle 2000)


    假如环不相交,那么可以将每个环上的边分成一个集合。把集合大小求(gcd)即可。

    当两个环相交的时候,发现原本的两个集合(S_1,S_2)要分成三类:(S_1igcap S_2,S_1setminus S_1igcap S_2,S_2setminus S_1igcap S_2)

    推广到更多的环,可以发现:两条边在同一个集合,当且仅当包含它们的环的集合相同。

    问题变为求出所有的集合(注意忽略桥边)。

    到了这里我卡住了。%%%ymq秒掉。

    判断两条边(a,b)是否在同一集合(称其为等价类)。先删(a)看看(b)是否在环中,再删(b)看看(a)是否在环中。如果都不在,那么它们为等价类。时间(O(m^2))

    还有更妙的做法:建dfs树,对于非树边随机赋一个权值,将其跨过的树边的权值都异或上这个权值。最终权值相同的为等价类。

    简要说明正确性:首先两条非树边不可能为等价类,因为非树边可以和树边组成环;其次不需要考虑两条或以上非树边所组成的环,因为这个环一定可以拆成多个只有一条非树边的环,并且每个环覆盖的树边为这个环覆盖的树边的子集。

    时间(O(m+mlg m))(后面这个(lg)map


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 2005
    int gcd(int a,int b){
    	int k;
    	while (b)
    		k=a%b,a=b,b=k;
    	return a;
    }
    int n,m;
    struct EDGE{
    	int to;
    	EDGE *las;
    } e[N*2];
    int ne;
    EDGE *last[N];
    void link(int u,int v){
    	e[ne]={v,last[u]};
    	last[u]=e+ne++;
    }
    int era;
    int bz[N][N];
    int dfn[N],low[N],cnt;
    void dfs(int x,int fa,int bz[]){
    	low[x]=dfn[x]=++cnt;
    	for (EDGE *ei=last[x];ei;ei=ei->las){
    		if (ei-e>>1==era || ei->to==fa)
    			continue;
    		if (!dfn[ei->to]){
    			dfs(ei->to,x,bz);
    			low[x]=min(low[x],low[ei->to]);
    			if (low[ei->to]<=dfn[x])
    				bz[ei-e>>1]=1;
    		}
    		else{
    			low[x]=min(low[x],dfn[ei->to]);
    			bz[ei-e>>1]=1;
    		}
    	}
    }
    int dsu[N],c[N];
    int getdsu(int x){return dsu[x]==x?x:dsu[x]=getdsu(dsu[x]);}
    void work(int x){
    	era=x;
    	memset(dfn,0,sizeof(int)*(n+1));
    	cnt=0;
    	for (int i=1;i<=n;++i)
    		if (!dfn[i])
    			dfs(i,0,bz[x]);
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	freopen("right.txt","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=0;i<m;++i){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		link(u,v),link(v,u);
    	}
    	work(m);
    	for (int i=0;i<m;++i)
    		if (bz[m][i])
    			work(i);
    //	for (int i=0;i<=m;++i,printf("
    "))
    //		for (int j=0;j<m;++j)
    //			printf("%d ",bz[i][j]);
    	for (int i=0;i<m;++i)
    		dsu[i]=i;
    	for (int i=0;i<m;++i)
    		if (bz[m][i])
    			for (int j=0;j<m;++j)
    				if (bz[m][j] && bz[i][j]==0 && bz[j][i]==0)
    					dsu[getdsu(i)]=getdsu(j);
    	for (int i=0;i<m;++i)
    		if (bz[m][i])
    			c[getdsu(i)]++;
    	int g=0;
    	for (int i=0;i<m;++i)
    		if (bz[m][i])
    			g=gcd(g,c[i]);
    	printf("1");
    	for (int i=2;i<=m;++i)
    		if (g%i==0)
    			printf(" %d",i);
    	return 0;
    }
    
    
    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <ctime>
    #include <map>
    #define N 2005
    #define ll long long
    #define irand (rand()*RAND_MAX+rand())
    #define lrand ((ll)irand*RAND_MAX*RAND_MAX+irand)
    int gcd(int a,int b){
    	int k;
    	while (b)
    		k=a%b,a=b,b=k;
    	return a;
    }
    int n,m;
    struct EDGE{
    	int to;
    	EDGE *las;
    } e[N*2];
    int ne;
    EDGE *last[N];
    void link(int u,int v){
    	e[ne]={v,last[u]};
    	last[u]=e+ne++;
    }
    ll v[N],s[N];
    map<ll,int> ma;
    int vis[N],ins[N];
    void dfs(int x,int fa=0){
    	vis[x]=1;
    	ins[x]=1;
    	for (EDGE *ei=last[x];ei;ei=ei->las){
    		if (ei->to==fa) continue;
    		if (!vis[ei->to]){
    			dfs(ei->to,x);
    			s[x]^=v[ei-e>>1]=s[ei->to];
    		}
    		else if (ins[ei->to]){
    			s[ei->to]^=v[ei-e>>1]=lrand;
    			s[x]^=v[ei-e>>1];
    		}
    	}
    	ins[x]=0;
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	freopen("out.txt","w",stdout);
    	srand(time(0));
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;++i){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		link(u,v),link(v,u);
    	}
    	for (int i=1;i<=n;++i)
    		if (!vis[i])
    			dfs(i);
    	for (int i=0;i<m;++i)
    		if (v[i])
    			ma[v[i]]++;
    	int g=0;
    	for (auto p=ma.begin();p!=ma.end();++p)
    		g=gcd(g,p->second);
    	printf("1");
    	for (int i=2;i<=m;++i)
    		if (g%i==0)
    			printf(" %d",i);
    	return 0;
    }
    
    
  • 相关阅读:
    PMP(第六版)十大知识领域、五大项目管理过程组、49个过程矩阵
    快速开发平台分享-UCML快速开发七种武器
    敏捷开发干货-快速开发平台的主题行为模型介绍
    MACHINE LEARNING
    What is “Neural Network”
    VS打开项目或解决方案卡死,一直处于未响应状态。
    Sql Server 本地(客户端)连接服务器端操作
    阿里云服务器,Sql Server 本地连接服务器端问题记录
    <%@ Register TagPrefix="uc1" TagName="user" Src="../Control/user.ascx" %>什么意思?
    IIS网站部署后,程序常见错误记录
  • 原文地址:https://www.cnblogs.com/jz-597/p/14042426.html
Copyright © 2011-2022 走看看