Codeforces Round #694 (Div. 2) D,F

  • D.Strange Definition
  • F.Strange Housing

D.Strange Definition

题意:
定义“相邻元素”:如果(frac{lcm(a,b)}{gcd(a,b)})是一个平方数,则称a,b相邻。
给一个长度为n序列a[i],d[i]为序列中与a[i]相邻元素的个数,这个序列每秒变化一次,每个元素变化方式为变成自己与自己所有相邻元素的乘积,现在有q次询问,求每次询问给一个x,输出第x秒序列中最大的d[i]。
题解:
1: (frac{lcm(a,b)}{gcd(a,b)} = frac{a*b}{gcd(a,b)^2}) 转化条件为: 将a,b质因数分解后,所有质因子在a,b中的奇偶性相同,则a,b相邻
2: 为了具体化这一条件,我们把一个数质因数分解,将所有出现次数为奇数次的因子相乘,比如 (540=4^2*3^3*5^1),出现奇数次的因子为3,5,得到(3*5=15),我们把它叫做“奇积”,可以发现不同的数得到的这个数如果相等,那他们一定相邻
3: 得到上面条件后,利用map将上面的数轻易分组,但要怎么处理变化后的数组呢,可以发现分组后大小为奇数的组别(除了“奇积”为1的)不管怎么变化,都不会和其他组相邻,大小为偶的和“奇积”为1的在一次变化后全部相邻,因此(x==0)时一个答案,(x!=0)时一个答案。

#include<bits/stdc++.h>
using namespace std;
#define f(i,a,b) for(register int i=a;i<=b;++i)
#define ll long long
#define N 300005
#define INF 999999999
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline ll read(){ll x;scanf("%lld",&x);return x;}
map<ll,ll>mmp;
ll ans1,ans2,Sum;
void Divide(ll x)
{
	ll sum=1,y=x;
	for(int i=2;i*i<=x;++i){
		if(x%i==0){
			int s=0;
			while(x%i==0) s++,x/=i;
			if(s&1) sum*=i; 
		}
	}
	if(x!=1) sum*=x;
	mmp[sum]++;
}
void solve()
{
	Sum=ans1=ans2=0;
	mmp.clear();
	ll n=read();
	f(i,1,n) Divide(read());
	for(auto mx:mmp)
	{
		ans1=max(ans1,mx.se);
		if(((mx.se)%2==0)||mx.fi==1)
			Sum+=mx.se;
	}
	ans2=max(ans1,Sum);
	ll q=read();
	f(i,1,q)
	{
		ll x=read();
		if(!x) printf("%lld
",ans1);
		else printf("%lld
",ans2);
	}
}
int main()
{
	ll T=read();
	while(T--) solve();
	return 0;
}

F.Strange Housing

PS:这题放F就离谱,明明很简单,无语
题意:给一个无向无权图,要求选取几个点染色使之满足以下条件:
1:每个点要么是染色点要么与被染色点相邻
2:图保持连通
3:染色点不能相邻
找出这个方案或输出“NO”
题解:从一个点出发dfs,vis标记是否遍历过,如果点的相邻点都没被染色,那这个点就染色,否则就不染色(染色vis[i]=2,不染色vis[i]=1),这条件1和条件3就肯定满足,至于条件2嘛,用十二指肠想想都知道肯定满足。

#include<bits/stdc++.h>
using namespace std;
#define f(i,a,b) for(register int i=a;i<=b;++i)
#define ll long long
#define N 300005
#define INF 999999999
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline ll read(){ll x;scanf("%lld",&x);return x;}
vector<ll>eg[N],Ans;
int vis[N];
void dfs(ll s)
{
	vis[s]=2;
	for(ll v:eg[s]){
		if(vis[v]==2) vis[s]=1;
	}
	for(ll v:eg[s]) if(!vis[v]) dfs(v);
}
void solve()
{
	ll n=read(),m=read();
	Ans.clear();
	f(i,1,n) vis[i]=0,eg[i].clear();
	f(i,1,m){
		ll x=read(),y=read();
		eg[x].pb(y);
		eg[y].pb(x);
	}
	dfs(1);
	int sum=0;
	f(i,1,n){
		if(!vis[i]){
		printf("NO
");
		return ;
		}
		if(vis[i]==2) Ans.pb(i);
	} 
	printf("YES
");
	int Siz=Ans.size();
	printf("%d
",Siz);
	for(ll x:Ans) printf("%lld ",x);printf("
");
}
int main()
{
	ll T=read();
	while(T--) solve();
	return 0;
}

本场比赛总结:

1:D题提到的“奇积”应该记住,在很多设计质因子奇偶性的问题时,“奇积”可以描述出这个性质
2:质因子的快速分解方法(适用于(a_i<10^6)时)
以前我采用的质因子分解都是一个一个(nsqrt{n})的爆炸性复杂度求解,当遇到(n<10^6)(a_i<10^6)时轻易爆炸,如果预处理出1e6前每个数的最大因子,分解时只遍历因子,就可以(nlogn)求解,预处理复杂度为(nlogn),代码如下

int Div[N];
void Divide(int x)
{
      while(Div[x])
      {
            int v=Div[x],sum=0;
            while(x%v==0) sum++,x/=v;
            ds.push_back(v);
            zs.push_back(sum);
      }
      if(x!=1) ds.push_back(x),zs.push_back(1);
}
int main()
{
      for(int i=2;i<=N;++i)
      {
            if(Div[i]) continue;
            for(int j=i;j<=N;j+=i)
                  Div[j]=i;
      }
}
原文地址:https://www.cnblogs.com/Tiork/p/14242744.html