$Codeforces$ $Round$ $620$ $Div.2$ 简要题解

从鸽王那儿看到的一组好题, (Itst) 推荐的,作为复健第一套题试试水。自己做了 (A)(B)(E) 三个,道阻且长。

(A-Two) (Rabbits)

解法

结论显然, ((a+b)|(y-x)) 时在整数秒相遇,相遇所用时间为 (frac{y-x}{a+b}) 秒;否则不能相遇。

(Code)

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
inline int read()
{
	int ret=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		ret=(ret<<1)+(ret<<3)+ch-'0';
		ch=getchar();
	}
	return ret*f;
}
int t,x,y,a,b;
int main()
{
	t=read();
	for(register int i=1;i<=t;i++)
	{
		x=read();
		y=read();
		a=read();
		b=read();
		y=y-x;
		b=a+b;
		if(y%b==0)
			printf("%d
",y/b);
		else
			printf("-1
");
	}
	return 0;
}

(B-) (Longest) (Palindrome)

解法

注意到 (n leqslant 100)(m leqslant 50) ,故考虑 (O(n^2m)) 逐字扫描任意两个串是否互为回文串,标记下来分左右两边输出,另外判断是否有本身就是回文串的字符串放在正中间即可。

(Code)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int ret=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		ret=(ret<<1)+(ret<<3)+ch-'0';
		ch=getchar();
	}
	return ret*f;
}
int n,m,cnt=0,slfnum=0,l[105],r[105];
char str[105][55];
bool flag,slf;
int main()
{
	n=read();
	m=read();
	for(register int i=1;i<=n;i++)
		scanf("%s",str[i]);
	for(register int i=1;i<=n;i++)
	{
		slf=1;
		for(register int j=0;j<m;j++)
			if(str[i][j]!=str[i][m-1-j])
				slf=0;
		if(slf)
			slfnum=i;
		for(register int j=i+1;j<=n;j++)
		{
			flag=1;
			for(register int k=0;k<m;k++)
				if(str[i][k]!=str[j][m-1-k])
					flag=0;
			if(flag)
			{
				cnt++;
				l[cnt]=i;
				r[cnt]=j;
			}
		}
	}
	if(slfnum==0)
		printf("%d
",2*m*cnt);
	else
		printf("%d
",2*m*cnt+m);
	for(register int i=1;i<=cnt;i++)
		printf("%s",str[l[i]]);
	if(slfnum>0)
		printf("%s",str[slfnum]);
	for(register int i=cnt;i>=1;i--)
		printf("%s",str[r[i]]);
	printf("
");
	return 0;
}

(C-) (Air) (Conditioner) (好题)

解法

首先提出引理:任一时刻可能达到的温度是一段连续(整数)区间。由于每一分钟到下一分钟的温度变化只能为 (+1)(-1)(0) ,故引理正确。由引理,将问题转化为任一时刻求出的可能区间是否满足顾客的需求,问题的实质是一个区间比较问题,时间复杂度 (O(q sum n)) 。具体求出可能的温度区间的方式是标记上下界,并随时间变化扩大上下界,随顾客需求变化缩小上下界。

提示

本题能做到线性的关键是不考虑具体的路径,只考虑路径的集合(以可能的温度区间呈现)。换言之,具体的合法路径是什么对于本题来说并不重要。

思考:上面做法的正确性?

个人认为在于最终所选路径只有合法和不合法两种,该做法筛去了所有不合法的路径(疑问:怎么证明?),只留下了保证是合法路径的路径集合。欢迎在评论区证明该题做法的正确性。

(Code)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int ret=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		ret=(ret<<1)+(ret<<3)+ch-'0';
		ch=getchar();
	}
	return ret*f;
}
int q,n,m,lm,rm,t[105],l[105],r[105];
bool flg;
int main()
{
	q=read();
	for(register int i=1;i<=q;i++)
	{
		n=read();
		m=read();
		t[0]=0;
		flg=1;
		for(register int j=1;j<=n;j++)
		{
			t[j]=read();
			l[j]=read();
			r[j]=read();
		}
		lm=m;
		rm=m;
		for(register int j=1;j<=n;j++)
		{
			lm=lm-(t[j]-t[j-1]);
			rm=rm+(t[j]-t[j-1]);
			if(r[j]<lm||rm<l[j])
				flg=0;
			lm=max(lm,l[j]);
			rm=min(rm,r[j]);
		}
		if(lm>rm)
			flg=0;
		if(flg)
			printf("YES
");
		else
			printf("NO
");
	}
	return 0;
}

(D-) (Shortest) (and) (Longest) (LIS) (好题)

解法

考虑怎样构造这个序列。(该题的考点是构造)下面分别讲解错误的和正确的思路。
错解:首先考虑怎样满足大小限制,再通过安排数的(相对)大小实现 (LIS) 最长/最短。
从错解走向正解:怎样安排数的(相对)大小呢?显然是使满足大小关系的小数放左边、大数放右边时 (LIS) 最长,最短的情况同理。
正解:反向考虑,首先不安排大小顺序,先考虑无大小限制时怎样使 (LIS) 最长/最短。显然,递增序列 (lbrace 1,2,3,...,n brace)(LIS) 最长,递减序列 (lbrace n,n-1,n-2,...,1 brace)(LIS) 最短。接下来考虑大小关系限制,对于构造好的序列,将连续 (">")(LIS) 最长序列的子序列反转、将连续 ("<")(LIS) 最短序列的子序列反转即可满足大小限制。

补充

(LIS) 长度的下界是连续 ("<") 的长度。达到该长度的构造如上。 (LIS) 长度的上界是连续 (">") 区间的个数加上连续 (">") 区间以外数的个数(另一种答案是 ("<") 的个数 (+1) )。达到该长度的构造如上。

(Code)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int ret=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		ret=(ret<<1)+(ret<<3)+ch-'0';
		ch=getchar();
	}
	return ret*f;
}
int t,n,l,lismin[200005],lismax[200005];
char str[200005];
bool flag,slf;
int main()
{
	t=read();
	for(register int i=1;i<=t;i++)
	{
		n=read();
		scanf("%s",str);
		for(register int j=1;j<=n;j++)
		{
			lismax[j]=j;
			lismin[j]=n+1-j;
		}
		l=0;
		for(register int j=0;j<n-1;j++)
		{
			if(str[j]=='<')
			{
				if(l==0)
					l=j+1;
			}
			else
			{
				if(l>0)
				{
					reverse(lismin+l,lismin+j+2);
					l=0;
				}
			}
		}
		if(l>0)
		{
			reverse(lismin+l,lismin+n+1);
			l=0;
		}
		for(register int j=0;j<n-1;j++)
		{
			if(str[j]=='>')
			{
				if(l==0)
					l=j+1;
			}
			else
			{
				if(l>0)
				{
					reverse(lismax+l,lismax+j+2);
					l=0;
				}
			}
		}
		if(l>0)
		{
			reverse(lismax+l,lismax+n+1);
			l=0;
		}
		for(register int j=1;j<n;j++)
			printf("%d ",lismin[j]);
		printf("%d
",lismin[n]);
		for(register int j=1;j<n;j++)
			printf("%d ",lismax[j]);
		printf("%d
",lismax[n]);
	}
	return 0;
}

(E) (1-Trees) (and) (Queries)

解法

思路简单,细节比较多。考虑加边 ((x,y)) 之后形成一个环,任意两点 (a,b) 之间的最短路径有三种可能: (a-x-y-b)(a-y-x-b)(a-b) 。由于同一条边、同一个点可以重复经过,这三种路径长度任意一个不比 (k) 大且与 (k) 的奇偶性相同即可。(这是一个简化的做法,因为可以无限前进偶数步,所以实际上只需考虑奇偶性)

细节

注意树的建图是双向的。注意倍增 (LCA) 的一些细节。

(Code)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int ret=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		ret=(ret<<1)+(ret<<3)+ch-'0';
		ch=getchar();
	}
	return ret*f;
}
int n,u,v,queries,x,y,a,b,k,dis1,dis2,dis3,rlen,r,edgenum,t;
int ver[200005],w[200005],nxt[200005],head[100005],d[100005],dist[100005],f[100005][18];
queue<int> q;
inline void addedge(int x,int y,int z)
{
	ver[++edgenum]=y;
	w[edgenum]=z;
	nxt[edgenum]=head[x];
	head[x]=edgenum;
}
inline void bfs()
{
	q.push(1);
	d[1]=1;
	while(q.size())
	{
		int x=q.front();
		q.pop();
		for(register int i=head[x];i;i=nxt[i])
		{
			int y=ver[i];
			if(d[y])
				continue;
			d[y]=d[x]+1;
			dist[y]=dist[x]+w[i];
			f[y][0]=x;
			for(register int j=1;j<=t;j++)
				f[y][j]=f[f[y][j-1]][j-1];
			q.push(y);
		}
	}
}
inline int lca(int x,int y)
{
	if(d[x]>d[y])
		swap(x,y);
	for(register int i=t;i>=0;i--)
		if(d[f[y][i]]>=d[x])
			y=f[y][i];
	if(x==y)
		return x;
	for(register int i=t;i>=0;i--)
	{
		if(f[y][i]!=f[x][i])
		{
			y=f[y][i];
			x=f[x][i];
		}
	}
	return f[x][0];
}
int main()
{
	n=read();
	for(register int i=1;i<n;i++)
	{
		u=read();
		v=read();
		addedge(u,v,1);
		addedge(v,u,1);
	}
	t=(int)(log(n)/log(2))+1;
	bfs();
	queries=read();
	for(register int i=1;i<=queries;i++)
	{
		x=read();
		y=read();
		a=read();
		b=read();
		k=read();
		dis1=dist[a]+dist[b]-2*dist[lca(a,b)];
		dis2=dist[a]+dist[x]-2*dist[lca(a,x)]+dist[y]+dist[b]-2*dist[lca(y,b)]+1;
		dis3=dist[b]+dist[x]-2*dist[lca(b,x)]+dist[y]+dist[a]-2*dist[lca(y,a)]+1;
		rlen=dist[x]+dist[y]-2*dist[lca(x,y)]+1;
		if((k>=dis1)&&((k-dis1)%2==0))
		{
			printf("YES
");
			continue;
		}
		if((k>=dis2)&&((k-dis2)%2==0))
		{
			printf("YES
");
			continue;
		}
		if((k>=dis3)&&((k-dis3)%2==0))
		{
			printf("YES
");
			continue;
		}
		printf("NO
");
	}
	return 0;
}

未完待续

原文地址:https://www.cnblogs.com/Peter0701/p/15144245.html