Codeforces Round #686(Div.3,CF1454)题解

由于第二天还要上学,就没有去打/kk

赛后补了一下,结果E没在规定时间内A掉(我搞了场虚拟赛),F到是切掉了……自闭了。

Solution

A

水题,直接输出 2 , 3 , 4 … … , n , 1 2,3,4……,n,1 2,3,4,n,1即可。

B

先跑出最小值,并且用一个桶记录数组中每个数是否出现过;最后扫一遍,找到等于最小值并且出现次数只有 1 1 1次的数即可。注意输出的是位置而不是值

C

n n n个桶,每个桶里面维护的是很多个区间;更详细地说,第 i i i个桶中存下来了所有值都是 i i i的区间,用许多二元组表示。

然后对于每一个 k k k,求出这 k k k个区间将整个序列分成了多少块即可(这 k k k个区间不算在内)。

时间复杂度 O ( ∑ n ) O(\sum n) O(n)

D

首先我们要发现一个性质: 若将答案序列从小到大排序,那么除去最后一个数外,其他的数都是 n n n的质因数中指数(幂次)最高的质因数 p p p,最后一个数是 n n n除以前面的所有数的乘积。

于是我们质因数分解,求出 p p p以及 p p p的最大指数质因数 t t t。答案序列就是 t − 1 t-1 t1 p p p与一个 n p t − 1 \frac n {p^{t-1}} pt1n

时间复杂度 O ( ∑ n ) O(\sum \sqrt n) O(n )

E

一道基环树的比较套路的题目。

首先,我们用并查集将这唯一的一个环缩成一个点,定义这个点为环点 x x x。令 x x x为根。在此时形成的树中,如果去掉环点 x x x,对于剩下的所有子树内的任何两个节点,都只有一种到达方式,即不能经过多余的那一条边,否则形成的就不是一个简单路径。对于任何两个跨子树的节点对,或者有一个是 x x x的节点对都可以经过环,即多出现了一种走法。同时,对于环点 x x x任何一个其他节点,也都只有一种到达方式

假设对于 x x x的每一个儿子的子树大小为 s i z siz siz,那么答案就是

n ( n − 1 ) − ∑ ( s i z + 1 ) s i z 2 n(n-1)-\sum \frac {(siz+1)siz} 2 n(n1)2(siz+1)siz

可以这么理解: 假设任意两个点之间都有两种走法。那么的对于两个节点属于同一个子树的节点对就被多算了,要减去这种情况。

时间复杂度 O ( ∑ n log ⁡ n ) O(\sum n \log n) O(nlogn)。当然如果你的并查集用了按秩合并(启发式合并)的优化,可以优化到 O ( ∑ n ) O(\sum n) O(n)

F

为了方便叙述,这里的 x x x的定义与题目中的 x x x相同,但 y y y的定义变成了第三个段的左端点

首先,我们枚举这个 x x x,并尝试快速求出 y y y

我们处理前缀最大值后缀最大值,并将后缀最大值用桶记录下来,第 i i i个桶记录下了所有后缀最大值为 i i i的位置。假设 1 − x 1-x 1x的最大值为 a a a,那么后 y y y个数的最大值也必须为 a a a,即 y y y必须在第 a a a个桶中找。

考虑确定了 x x x后,如果 y y y单调向右,那么区间 [ x + 1 , y − 1 ] [x+1,y-1] [x+1,y1]即第二段的最小值单调不增。而这个最小值也是确定的,所以我们可以二分。每次的 c h e c k check check,相当于静态的区间查询最小值,可以采用RMQ来解决。

综上所述,我们通过 v e c t o r vector vector内二分套上一个 R M Q RMQ RMQ,得到了复杂度为 O ( ∑ ( n log ⁡ n ) ) O(\sum (n \log n)) O((nlogn))的算法,可以轻松通过本题。

Code

A&&B&&C

咕咕咕

D

#include <bits/stdc++.h>
#define int long long
using namespace std;

int t,n;

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		
		int maxv=0,pos=0,tot=n;
		for (int i=2;i*i<=n;i++)
		{
			if (n%i==0)
			{
				int cnt=0; 
				while (n%i==0)  n/=i,cnt++;
				
				if (cnt>maxv)  maxv=cnt,pos=i;
			}
		}
		if (n>1)
		{
			int cnt=1;
			if (cnt>maxv)  maxv=cnt,pos=n;
		}
		cout<<maxv<<endl;
		for (int i=1;i<=maxv-1;i++)  cout<<pos<<' ',tot/=pos;
		cout<<tot<<endl;
	}
	return 0;
}

E

#include <bits/stdc++.h>
#define int long long
using namespace std;

int read()
{
	int s=0,w=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-')  w=-w;ch=getchar();}
	while (ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch%'0');ch=getchar();}
	return s*w;
}

int t,n,cnt=0,u,v,root;
int head[200005],fa[200005],siz[200005],vis[200005],with[200005];

struct edge{int next,to;}e[400005];
void add_edge(int x,int y){cnt++;e[cnt].to=y,e[cnt].next=head[x],head[x]=cnt;}
void clear()
{
	for (int i=1;i<=n;i++)  head[i]=vis[i]=siz[i]=with[i]=0;
	for (int i=1;i<=cnt;i++)  e[i].to=e[i].next=0;
	cnt=0;
}

int fin(int x)
{
	if (x==fa[x])  return x;
	else return fa[x]=fin(fa[x]);
}

void dfs(int now,int fath)
{
	if (now==v)  with[now]=1;
	for (int i=head[now];i;i=e[i].next)
	{
		if (e[i].to!=fath)
		{
			dfs(e[i].to,now);
			if (with[e[i].to])  with[now]=1;
		}
	}
}

void dfs2(int now,int fath)
{
	vis[now]=1;
	for (int i=head[now];i;i=e[i].next)
	  if (e[i].to!=fath&&with[e[i].to])  dfs2(e[i].to,now);
}

void dfs3(int now,int fath)
{
	siz[now]=1;
	for (int i=head[now];i;i=e[i].next)
	{
		int y=e[i].to;
		if (y!=fath&&!vis[y])
		  dfs3(y,now),siz[now]+=siz[y];
	}
}

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		clear();
		for (int i=1;i<=n;i++)  fa[i]=i;
		for (int i=1;i<=n;i++)
		{
			int x=read(),y=read();
			int fx=fin(x),fy=fin(y);
			
			if (fx!=fy)
			  add_edge(x,y),add_edge(y,x),fa[fx]=fy;
			else u=x,v=y;
		}
		dfs(u,0);
		dfs2(u,0);
		
		int ans=n*(n-1);
		for (int i=1;i<=n;i++)
			if (vis[i])  dfs3(i,0),ans-=((siz[i]*(siz[i]-1))/2);
		cout<<ans<<endl;
	}
	return 0;
}

F

#include <bits/stdc++.h>
#define int long long
using namespace std;

int t,n;

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		
		int maxv=0,pos=0,tot=n;
		for (int i=2;i*i<=n;i++)
		{
			if (n%i==0)
			{
				int cnt=0; 
				while (n%i==0)  n/=i,cnt++;
				
				if (cnt>maxv)  maxv=cnt,pos=i;
			}
		}
		if (n>1)
		{
			int cnt=1;
			if (cnt>maxv)  maxv=cnt,pos=n;
		}
		cout<<maxv<<endl;
		for (int i=1;i<=maxv-1;i++)  cout<<pos<<' ',tot/=pos;
		cout<<tot<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值