codeforces 628.div2

A. EhAb AnD gCd

题意:给定一个x,求两个正整数a,b,满足a、b的最大公因子和最小公倍数之和等于x
题解:a=1,b=x-1,即可满足

B. CopyCopyCopyCopyCopy

题意:给定一个长度为n的串a,可以得到一个由n个a相连组成的新串,求新串中最长的递增子序列
题解:最长的递增序列,表明同种元素只能出现一次,且a中元素的种类必定小于等于n。
	 将a排序后,按顺序从新串的第i个(i:1~n)a中取出a[i]。即a的元素种类即为新串的最长递增子序列
#include<bits/stdc++.h>
#define ll long long int
#define _DEBUG

#define vi		vector<int>
#define vl		vector<ll> 
#define vvi		vector<vi>
#define pii		pair<int,int>
#define pll		pair<ll,ll>
#define pil		pair<int,ll>
#define pli		pair<ll,int>

#define pb		push_back
#define mp		make_pair

#define fore(index_i,index_l,index_r)	for(int index_i=int(index_l);index_i<int(index_r);index_i++)
#define forn(i,n)	fore(i,0,n)
#define sz(a)		(int)(a).size()
#define all(a)		(a).begin(),(a).end()
#define mem(a,i)	memset(a,i,sizeof(a))
#define fout(a,n)	forn(index_fi,n)cout<<a[index_fi]<<' ';cout<<endl;
#define ffout(a,n,m)	forn(index_ffi,n){forn(index_ffj,m)cout<<a[index_ffi][index_ffj]<<' ';cout<<endl;}cout<<endl;
#define out(i)		cout<<i<<endl;
 
#define Pi		acos(-1.0)

using namespace std;
const int MOD=int(1e9)+7;
const ll  MOD64=(ll)(1e18)+7;
const int INF=0x7fffffff;
const ll INF64=0x7fffffffffffffff;

void file()
{
#ifdef _DEBUG
    freopen("cin.txt","r",stdin);
    //  freopen("cout.txt","w",stdout);
#endif
}

const int N = 1e5+10;
int a[N];

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		forn(i,n)cin>>a[i];

		sort(a,a+n);

		int ans=unique(a,a+n)-a;
		cout<<ans<<endl;
	}

	return 0;
}

C. Ehab and Path-etic MEXs

题意:给定一个由n个点组成的树,现给树上每条边赋值,值的取值范围为0~n-2,每条边的值不相同。
	求所有点对的最大MEX值最小。
	MEX(u,v):在树中,u到v的简单路径上的所有边值中,不被包含的最大自然数。
	eg:	边值为0,1,2,那么MEX(u,v)=3
			边值为1,2,那么MEX(u,v)=0
#include<bits/stdc++.h>
#define ll long long int
#define _DEBUG

#define vi		vector<int>
#define vl		vector<ll> 
#define vvi		vector<vi>
#define pii		pair<int,int>
#define pll		pair<ll,ll>
#define pil		pair<int,ll>
#define pli		pair<ll,int>

#define pb		push_back
#define mp		make_pair

#define fore(index_i,index_l,index_r)	for(int index_i=int(index_l);index_i<int(index_r);index_i++)
#define forn(i,n)	fore(i,0,n)
#define sz(a)		(int)(a).size()
#define all(a)		(a).begin(),(a).end()
#define mem(a,i)	memset(a,i,sizeof(a))
#define fout(a,n)	forn(index_fi,n)cout<<a[index_fi]<<' ';cout<<endl;
#define ffout(a,n,m)	forn(index_ffi,n){forn(index_ffj,m)cout<<a[index_ffi][index_ffj]<<' ';cout<<endl;}cout<<endl;
#define out(i)		cout<<i<<endl;
 
#define Pi		acos(-1.0)

using namespace std;
const int MOD=int(1e9)+7;
const ll  MOD64=(ll)(1e18)+7;
const int INF=0x7fffffff;
const ll INF64=0x7fffffffffffffff;

void file()
{
#ifdef _DEBUG
    freopen("cin.txt","r",stdin);
    //  freopen("cout.txt","w",stdout);
#endif
}
/*
1、MEX(u,v)=i,代表u~v的简单路径上,包含0、1...i-1,那么用贪心的思想
   让小的自然数之间的路径,尽可能的少,且在不同的路径上,
   即把他们放在叶节点上 
*/ 
const int N = 2e5+10;
vector<pii> a[N];
int ans[N];
bool vis[N];

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	int n;
	scanf("%d",&n);
	int x,y;
	forn(i,n-1)
	{
		scanf("%d %d",&x,&y);
		a[x].pb(mp(y,i));
		a[y].pb(mp(x,i));
	}
	mem(ans,-1);
	
	if(n==2)//只有两个点的树的特判,此时只有一条边 
	{
		printf("0\n");
		return 0;
	}
	int num=0;
	fore(i,1,n+1)
	{
		if(sz(a[i])==1)
		{
			ans[a[i][0].second]=num;//每个叶节点上放一个小的自然数 
			num++;
		}
	}

	forn(i,n-1){
		if(ans[i]==-1)printf("%d\n",num++);//其余的节点就随意放 
		else printf("%d\n",ans[i]);
	}


	return 0;
}

D. Ehab the Xorcist

题意:给定u和v,找到最短的数组,使得元素的异或和为u,和为v。若没有解,输出-1
题解:1、u>v,不可能存在异或和大于和的情况,没有解
	2、u==v==0,输出0
	3、u==v!=0,数组为{u}
	4、由于是异或,从2进制的角度来考虑。
		如果u的第i位为1,那么结果的所有元素的第i位为1的个数必定是奇数个
		           为0,                                    偶数个
		那么把这些位提出来,和刚好为u,剩下的值的异或和必须为0,和为v-u
		那么把v-u除以2,如果没有余数,则刚好满足,如果由余数,则无法满足,没有解
		再考虑将u的值和(v-u)/2合并,如果没有进位,则可以合并,否则不行
#include<bits/stdc++.h>
#define ll long long int
#define _DEBUG

#define vi		vector<int>
#define vl		vector<ll> 
#define vvi		vector<vi>
#define pii		pair<int,int>
#define pll		pair<ll,ll>
#define pil		pair<int,ll>
#define pli		pair<ll,int>

#define pb		push_back
#define mp		make_pair

#define fore(index_i,index_l,index_r)	for(int index_i=int(index_l);index_i<int(index_r);index_i++)
#define forn(i,n)	fore(i,0,n)
#define sz(a)		(int)(a).size()
#define all(a)		(a).begin(),(a).end()
#define mem(a,i)	memset(a,i,sizeof(a))
#define fout(a,n)	forn(index_fi,n)cout<<a[index_fi]<<' ';cout<<endl;
#define ffout(a,n,m)	forn(index_ffi,n){forn(index_ffj,m)cout<<a[index_ffi][index_ffj]<<' ';cout<<endl;}cout<<endl;
#define out(i)		cout<<i<<endl;
 
#define Pi		acos(-1.0)

using namespace std;
const int MOD=int(1e9)+7;
const ll  MOD64=(ll)(1e18)+7;
const int INF=0x7fffffff;
const ll INF64=0x7fffffffffffffff;

void file()
{
#ifdef _DEBUG
    freopen("cin.txt","r",stdin);
    //  freopen("cout.txt","w",stdout);
#endif
}

const int N = 1e5+10;
ll fp[70];

void init()//fp[i]=2^i 
{
	fp[0]=1;
	fore(i,1,61)fp[i]=fp[i-1]<<1;

	//fout(fp,61);
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	ll u,v;
	cin>>u>>v;
	init();

	if(u>v)
	{
		cout<<-1<<endl;
		return 0;
	}
	if(u==v)
	{
		if(u==0)cout<<0<<endl;
		else
			cout<<1<<endl<<u<<endl;
		return 0;
	}

	ll a=0,b=0,c=0;
	ll tv=v-u;
	if(tv%2==1)
	{
		cout<<-1<<endl;
		return 0;
	}
	a=b=tv/2;
	forn(i,61)
	{
		if(fp[i]>u)break;

		if(fp[i]&u)//如果u的第i位为1 
		{
			if(fp[i]&a)//如果(v-u)/2的第i位为1,则无法合并, 
				c+=fp[i];
			else a+=fp[i];
		}
		
	}

	if(c==0)cout<<2<<endl<<a<<' '<<b<<endl;
	else cout<<3<<endl<<a<<' '<<b<<' '<<c<<endl;

	return 0;
}

E. Ehab’s REAL Number Theory Problem

题意:给出n个元素组成的数组,每个元素最多只有7个因子,找到最短的子序列,使得子序列中元素之积为平方数。
		输出子序列的长度
题解:首先将每个元素考虑成多个质数之和
	每个元素最多只有7个因子,即每个元素最多由两个质数组成。
	如果有3个,即u=a*b*c,那么公因子有1,a,b,c,a*b,a*c,b*c,u, 一共八个
	将元素中的平方数因子提出来,剩下的只有1,p,p*q,q和p都是质数。如果有1,那么答案就是这个数了
	那么将每个质数看成是一个点,再加上1这个点,那么对于每个元素,都看成是图上两个点的积,
	即将这两个点,连接起来。
	那么题目就变成了,在这个图上的最小循环。
	题目的范围是n=O(10^5),每个元素x=O(10^6),
	10^6以内的质数个数是O(10^4) (9000多个),不可能用Dijkstra算法来做(O(10^4^3)),
	这里考虑一个优化,大于1000的质数之间,是不存在边的
	那么我们用1000以内的质数,来作为源点,来做bfs,(O(10^3*10^5))
#include<bits/stdc++.h>
#define ll long long int
#define _DEBUG

#define vi		vector<int>
#define vl		vector<ll> 
#define vvi		vector<vi>
#define pii		pair<int,int>
#define pll		pair<ll,ll>
#define pil		pair<int,ll>
#define pli		pair<ll,int>

#define pb		push_back
#define mp		make_pair

#define fore(index_i,index_l,index_r)	for(int index_i=int(index_l);index_i<int(index_r);index_i++)
#define forn(i,n)	fore(i,0,n)
#define sz(a)		(int)(a).size()
#define all(a)		(a).begin(),(a).end()
#define mem(a,i)	memset(a,i,sizeof(a))
#define fout(a,n)	forn(index_fi,n)cout<<a[index_fi]<<' ';cout<<endl;
#define ffout(a,n,m)	forn(index_ffi,n){forn(index_ffj,m)cout<<a[index_ffi][index_ffj]<<' ';cout<<endl;}cout<<endl;
#define out(i)		cout<<i<<endl;
 
#define Pi		acos(-1.0)

using namespace std;
const int MOD=int(1e9)+7;
const ll  MOD64=(ll)(1e18)+7;
const int INF=0x7fffffff;
const ll INF64=0x7fffffffffffffff;

void file()
{
#ifdef _DEBUG
    freopen("cin.txt","r",stdin);
    //  freopen("cout.txt","w",stdout);
#endif
}

const int N = 1e6+10;
int d[N],pr[N];
int one_p[N];
int dist[N][2];
int ans = N;
queue<int> q;
vi g[N];
int n;

void init()//求10^6以内的质数,pr[i]表示第i个质数是pr[i],总共n个,
		   //d[j]表示j的最小质数在pr数组中的坐标 
{
	n=0;
	mem(d,-1);
	fore(i,2,N)
	{
		if(d[i]!=-1)continue;
		pr[n]=i;
		for(int j=i;j<N;j+=i)
		{
			if(d[j]==-1)
				d[j]=n;
		}
		n++;
	}
}

void bfs(int root)
{
	while(!q.empty())
	{
		int v=q.front();
		q.pop();
		forn(i,sz(g[v]))
		{
			int u=g[v][i];
			if(u==root)continue;//源点的子节点都访问过了,不用再访问源点了 
			if(dist[u][1]==-1)//新的节点 
			{
				dist[u][0]=dist[v][0]+1;
				dist[u][1]=dist[v][1];
				q.push(u);
			}
			else if(dist[u][1]!=dist[v][1])//出现环 
			{
				ans=min(ans,dist[v][0]+dist[u][0]+3);
			}
		}
	}
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	init();
	int m;
	cin>>m;
	forn(i,m)
	{
		int x;
		cin>>x;
		vi a;
		while(x>1)
		{
			int id=d[x];
			int t=0;
			while(x%pr[id]==0)
			{
				t^=1;//异或来表示个数,1:奇数个,0:偶数个 
				x=x/pr[id];
			}
			if(t==1)a.pb(id);
		}

		if(sz(a)==0)//x刚好为平方数 
			ans=1;
		else if(sz(a)==1)//x=1*a[0] 
			one_p[a[0]]++;
		else if(sz(a)==2)//x=a[0]*a[1]
		{
			g[a[0]].pb(a[1]);
			g[a[1]].pb(a[0]);
		}
		//cout<<i<<' ';fout(a,sz(a));
	}

	if(ans==1)
	{
		cout<<"1\n";
		return 0;
	}

	forn(i,n)
	{
		if(one_p[i]>=2)//存在两个1*one_p[i] 
		{
			cout<<"2\n";
			return 0;
		}
	}
	//out(1);
	
	//当1做为源点时 
	while(!q.empty())q.pop();
	forn(i,n)
	{
		//out(i);
		dist[i][0]=N;//dist[i][0]表示第i个质数到源点的距离 
		dist[i][1]=-1;//dist[i][1]表示第i个质数属于源点的哪一个子节点 
		if(one_p[i]>0)
		{
			dist[i][0]=0;//这里为0,和后面出现环的时候的+3对应 
			dist[i][1]=i;
			q.push(i);
		}
	}
	bfs(-1);
	
	forn(i,n)
	{
		if(pr[i]*pr[i]>N)break;

		while(!q.empty())q.pop();
		forn(j,n)
		{
			dist[j][0]=N;
			dist[j][1]=-1;
		}
		forn(j,sz(g[i]))
		{
			int u=g[i][j];
			if(dist[u][0]!=N)
			{
				ans=min(ans,2);
				continue;
			}
			dist[u][0]=0;
			dist[u][1]=u;
			q.push(u);
		}
		bfs(i);
	}

	if(ans==N)ans=-1;
	cout<<ans<<endl;

	return 0;
}

F.Ehab’s Last Theorem

题意:给定一个n个点,m条边的无向图,sq=⌈√n⌉ .考虑两个问题:
	1、是否存在个数刚好为sq的独立数组,即数组元素两两没有边相连
	2、是否存在节点数不少于sq的简单环,环上每个点都只经过一次
	保证没有自循环和重复边,且图已连接,选择一个问题并给出答案
题解:dfs找环,bfs找独立数组
(吐槽一下,这道题明显比E题要难一点,E题还要建模)
#include<bits/stdc++.h>
#define ll long long int
#define _DEBUG

#define vi		vector<int>
#define vl		vector<ll> 
#define vvi		vector<vi>
#define pii		pair<int,int>
#define pll		pair<ll,ll>
#define pil		pair<int,ll>
#define pli		pair<ll,int>

#define pb		push_back
#define mp		make_pair

#define fore(index_i,index_l,index_r)	for(int index_i=int(index_l);index_i<int(index_r);index_i++)
#define forn(i,n)	fore(i,0,n)
#define sz(a)		(int)(a).size()
#define all(a)		(a).begin(),(a).end()
#define mem(a,i)	memset(a,i,sizeof(a))
#define fout(a,n)	forn(index_fi,n)cout<<a[index_fi]<<' ';cout<<endl;
#define ffout(a,n,m)	forn(index_ffi,n){forn(index_ffj,m)cout<<a[index_ffi][index_ffj]<<' ';cout<<endl;}cout<<endl;
#define out(i)		cout<<i<<endl;
 
#define Pi		acos(-1.0)

using namespace std;
const int MOD=int(1e9)+7;
const ll  MOD64=(ll)(1e18)+7;
const int INF=0x7fffffff;
const ll INF64=0x7fffffffffffffff;

void file()
{
#ifdef _DEBUG
    freopen("cin.txt","r",stdin);
    //  freopen("cout.txt","w",stdout);
#endif
}

const int N = 1e6+10;
vi v[N];
int sq,dep[N];
bool mark[N];//标记数组,标记为1表示不要,为0表示要 
int n,m;
stack<int> s;

void dfs(int x)
{
	s.push(x);
	dep[x]=s.size();
	forn(i,sz(v[x]))
	{
		int u=v[x][i];
		if(!dep[u])dfs(u);
		else if(dep[x]-dep[u]+1>=sq)//出现环,且环的长度大于sq 
		{
			cout<<2<<endl<<dep[x]-dep[u]+1<<endl;
			fore(i,dep[u]-1,dep[x])
			{
				int y=s.top();
				s.pop();
				cout<<y<<' ';
			}
			cout<<endl;
			exit(0);
		}
	}

	if(!mark[x])//对于要的节点,给相连的节点上标记1,保证不会出现要的点相连, 
	{
		forn(i,sz(v[x]))
			mark[v[x][i]]=true;
	}
	s.pop();
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	int x,y;
	forn(i,m)
	{
		cin>>x>>y;
		v[x].pb(y);
		v[y].pb(x);
	}

	mem(mark,false);
	mem(dep,0);
	sq=0;
	while(sq*sq<n)sq++;

	dfs(1);

	cout<<1<<endl;
	for(int i=1;sq;i++)
	{
		if(!mark[i])
		{
			cout<<i<<' ';
			sq--;
		}
	}
	cout<<endl;

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值