zoukankan      html  css  js  c++  java
  • $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;
    }
    

    未完待续

  • 相关阅读:
    北京燃气IC卡充值笔记
    随机分析、随机控制等科目在量化投资、计算金融方向有哪些应用?
    量化交易平台大全
    Doctor of Philosophy in Computational and Mathematical Engineering
    Institute for Computational and Mathematical Engineering
    Requirements for the Master of Science in Computational and Mathematical Engineering
    MSc in Mathematical and Computational Finance
    万字长文:详解多智能体强化学习的基础和应用
    数据处理思想和程序架构: 使用Mbedtls包中的SSL,和服务器进行网络加密通信
    31-STM32+W5500+AIR202/302基本控制篇-功能优化-W5500移植mbedtls库以SSL方式连接MQTT服务器(单向忽略认证)
  • 原文地址:https://www.cnblogs.com/Peter0701/p/15144245.html
Copyright © 2011-2022 走看看