Codeforces Round #486 (Div. 3)题解

这周趁着有Div3想上上分,过了3题,900多名。本以为这下上1400稳了吧,没想到最后一看Rating,1399.。。。看来想变成青名还得继续打喽(希望别再掉下去)。

言归正传,我们来看一下这次Div3的题解

题目链接:http://codeforces.com/contest/988

A题

这题确实比较水,由于输出任意一组就可以,那么就暴力了,使用used数组标记一下之前出现的元素就可以喽~

#include
using namespace std;
int main()
{
	int n,k;
	int cnt=0;
	int a[10000];
	int used[10000];
	int res[10000];
	int u=0;
	int flag=0;
	scanf("%d%d",&n,&k);
	for(int i=0;i

B题

应该是考字符串排序。若前一个能成为后一个的子串,那么前一个串的长度必定不大于后一个,根据这个首先排个序。

接下来就是字符串匹配了。可以暴力(因为串长度只有100),当然神犇也可以用KMP(觉得这道题写KMP稍微有些浪费时间)。

#include
using namespace std;
string a[110];
bool cmp(string x,string y)
{
	return x.size()> a[i];
	sort(a,a+n,cmp);
	if(n==1)
	{
	  printf("YES\n");
	  cout << a[0] <

C题

这道题比赛的时候用了很长时间才做出来,归根结底还是map用的不熟。

思路就是在线处理,每次读入一列数就把这列数去掉一个元素后可能的情况存入map。我开了两个map,一个存第几组,一个存在每组数中的位置,也就是下标。(后来看了网上的代码可以用pair存,窝太弱了。。。)每次读入一组新的数时,就看之前有没有就行了。

#include
using namespace std;
typedef long long ll;
map mp1;
map mp2;
ll a[200010];
int main()
{
	int n,r1,r2,r3,r4,t;
	int flag=0;
	scanf("%d",&t);
	for(ll i=1;i<=t;i++)
	{
		scanf("%d",&n);
		ll sum=0;
		for(ll j=1;j<=n;j++)
		{
		  scanf("%lld",&a[j]);
		  sum+=a[j];
	    }
	    if(flag==1)
	    continue;
	    for(ll j=1;j<=n;j++)
	    {
			 map::iterator  it=mp1.find(sum-a[j]);
			 if(it!=mp1.end())
		     {
		     	if(mp1[sum-a[j]]!=i)
		     	{
		           r1=mp1[sum-a[j]];
		           r2=mp2[sum-a[j]];
		           r3=i;
		           r4=j;
				   flag=1;
				   break;
			     }
			 }
			 else
			 {
			 	mp1[sum-a[j]]=i;
			 	mp2[sum-a[j]]=j;
			 }
		}		     
	}
	if(flag==0)
	printf("NO\n");
	else
	{
		printf("YES\n");
		printf("%d %d\n",r1,r2);
		printf("%d %d\n",r3,r4);
	}
	return 0;
} 

D题

可以说是一道数学题,也可以说是思维题

关键在于最多答案只有三个数且此时三个数成等差数列且公差为2的幂。(证明过程参考这位博主的博客)

https://blog.csdn.net/weixin_39453270/article/details/80548442

#include
using namespace std;
typedef long long ll;
ll a[200010];
set s;
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;itot)
		  {
			if(tem==1)
			{
				res[0]=a[i];
				if(t1)
				res[1]=a[i]+pre[j];
				if(t2)
				res[1]=a[i]+2*pre[j];
			}
			else
			{
				res[0]=a[i];
				res[1]=a[i]+pre[j];
				res[2]=a[i]+2*pre[j];
			}
			tot=tem;
		   }
	   }
	}
	if(tot==0)
	{
		printf("1\n%lld\n",a[0]);
	}
	else if(tot==1)
	{
		printf("2\n");
		printf("%lld %lld\n",res[0],res[1]);
	}
	else
	{
		printf("3\n");
		printf("%lld %lld %lld\n",res[0],res[1],res[2]);
	}
	return 0;
} 

E题

最开始想用BFS做,后来感觉过不了。后来看了别人的博客,发现是贪心。

关键在于能被25整除,那么末尾必是“00”,“25”,“50”。“75”。(这个应该很好理解)

那么我们就检查末两位,如果不是就把前面的数换到后面就好了,最后再对前导0处理一下就ok。详见代码

#include
typedef long long ll;
using namespace std;
string a;
string b;
int len;
int tot;
void make(char x,char y)
{
	int t1=0,t2=0,f=0;
	if(a[len-1]==y)
	{
		t2=0;
		f++;
	}
	else
	{
		for(int j=len-2;j>=0;j--)
		{
			if(a[j]==y)
			{
			   for(int k=j;k<=len-2;k++)
			   {
			      swap(a[k],a[k+1]);
			      t2++;
			    }
			   f++;
			   break;
		    }
		}
	}
	if(a[len-2]==x)
	{
		t1=0;
		f++;
	}
	else
	{
		for(int j=len-3;j>=0;j--)
		{
			if(a[j]==x)
			{
			   for(int k=j;k<=len-3;k++)
			   {
			      swap(a[k],a[k+1]);
			      t1++;
			    }
			   f++;
			   break;
		    }
		}
	}
	int ind;
	int ff=0;
	if(f==2)
	{
		if(a[0]!='0')
		tot=min(tot,t1+t2);
		else
		{
			for(int i=1;i<=len-3;i++)
			{
				if(a[i]!='0')
				{
					ind=i;
					ff=1;
					break;
				}
			}
			if(ff==1)
			{
				tot=min(tot,t1+t2+ind);
			}
		}
	}
}
int main()
{
	cin >> a;
	b=a;
	len=a.size();
	tot=1000000000;
	if(len==1)
	printf("-1\n");
	else
	{
		 make('0','0');
		 a=b;
		 make('2','5');
		 a=b;
		 make('5','0');
		 a=b;
		 make('7','5');
		 if(tot==1000000000)
		 printf("-1\n");
		 else
		 printf("%d\n",tot);
	}
	return 0;
} 

F题

又是dp题

参考了别人的博客,这道题有两种做法

(可以看看https://www.cnblogs.com/HDUjackyan/p/9125241.html这位大佬博客上的讲解,这里就直接搬过来了)

第一种

dp[i][j]表示从0到i时,在点i有第j把伞(没有伞时j==0)时的最小疲惫值

转移时,分成三种情况(即对应着三种操作)

dp[i+1][j]=min(dp[i+1][j],dp[i][j]+w[j])  (第i+1个点下雨,同时没带伞时不成立,其他条件都成立)  该操作是从第i个点到第i+1个点啥也不做,即第i+1个点的状态和第i个点的状态相同

dp[i+1][0]=min(dp[i+1][0],dp[i][j]) (当下一个点没下雨时成立) 该操作是在第i个点放下伞

dp[i+1][id[i]]=min(dp[i+1][id[i]],dp[i][j]+w[id[i]])  (在第i个点有伞) 该操作是第i个点有伞,拿起伞走到第i+1个点上去

#include
#define INF 10000000000
using namespace std;
typedef long long ll;
typedef struct
{ 
	 int ind;
	 int w; 
}  U;
U ubr[2010];
int rain[2010];
int ok[2010];
ll dp[2010][2010];
bool cmp(U x,U y)
{
	if(x.ind!=y.ind)
	return x.ind

第二种

这种我只是看了一下就口胡了,没有写。看完之后感觉甚至比第一种好理解?(想看代码的话直接看上面的博客就行)


你可能感兴趣的:(codeforce)