Codeforces Round #706 (Div. 2) A-D题解

题目链接:
https://codeforces.com/contest/1496

A

思路:
(1).对k的大小进行考虑。如果k=0,直接YES;如果2*k+1>n,直接NO。
(2)字符串是以ABA形式存在,所以判断字符串前半段与后半段是否对称。并且,对称的长度,num>=k。

AC代码:

	#include
	using namespace std;
	char s[110];
	int n,k,t;
	int main()
	{
     
		cin>>t;
		while(t--)
		{
     
			cin>>n>>k;
		
			cin>>s;
		//	cout<
			
			int flag=0;
			int num=0;
			for(int i=0;i<n/2;i++)
			{
     
				if(s[i]==s[n-1-i])
				num++;
				else 
				{
     
					flag=-1;
					break;
				}
			}
	//		printf("flag==%d\n",flag);
			if(num>=k&&!(n<2*k+1)) cout<<"YES"<<endl;
			else
			cout<<"NO"<<endl;
			
		}
		return 0;
	}

B

思路:
1.如果k=0,直接输出n.注意:这里a数组中的元素每个都是不同的(题目已经说了,我写的时候就没看到,导致一直WA)
2.如果a数组是以0.1.2.3.4连续的形式,可以手算一下,每一次的计算,都会产生新的最大值,就是会接着后面一个数继续增加1。所以,这种情况直接输出n+k。
3.如果上面两种都不满足,计算一下新的数,如果新的数在a数组中出现过,那么每次的操作都是这个数生成,答案不变,输出n。如果没有出现过,输出n+1。

ps:自己写的时候把四舍五入写错了。。。太粗心了//

AC代码:

#include
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll mp[N];
ll a[N];
ll t,n,k,mex,maxv;
int main()
{
     
	cin>>t;
	while(t--)
	{
     
		ll ans=0;
		cin>>n>>k;
		maxv=-1;
		memset(mp,0,sizeof(mp));
		for(int i=0;i<n;i++)
		{
     
			cin>>a[i];
		}
		if(k==0)
		{
     
			cout<<n<<endl;
			continue;
		}
		int flag=0;
		sort(a,a+n);
		for(int i=0;i<=n-1;i++)
		{
     
			if(a[i]!=i)
			{
     
				mex=i;
				flag=-1;
				break;
			}
		}
		if(flag==0)
		{
     
			n+=k;
			cout<<n<<endl;
			continue;
		}
		else
		{
     
			maxv=a[n-1];
		//	printf("mex===%d max===%d\n",mex,maxv);
			float h=(mex+maxv)*1.0/2;
			//printf("h==%d\n",h);
			int p= int(h+0.5);
		//	printf("p===%d\n",p);
		 flag=0;
		for(int i=0;i<n;i++)
		{
     
			if(a[i]==p)
			{
     
				flag=-1;
			}
		}
			if(flag==-1)
			{
     
				cout<<n<<endl;
			}
			else
			{
     
				cout<<n+1<<endl;
			}
		}
			
		}
return 0;	}

C

思路:随便找几个数算一下,例如(5,0)(1,0)(0,1)(0,2),就可以发现,X上离原点近的和Y上离原点近的相连,这样得出来的路程最短。
所以两个数组排序一下,然后累加就ok。

ps:输入数组的时候不能用 cin 不然会超时,又吃了这个亏。。。

AC代码

//C. Diamond Miner
#include
using namespace std;
const int N=1e5+10;
typedef long long ll;
double x[N],y[N];
int n,t,cnt1,cnt2;
double a,b;
int main()
{
     
	cin>>t;
	while(t--)
	{
     
		cnt1=0;
		cnt2=0;
		cin>>n;
		for(int i=1;i<=2*n;i++)
		{
     
			
			scanf("%lf%lf",&a,&b);
			if(a==0) 
			{
     
				y[++cnt1]=abs(b);
			}
			else 
			{
     
				x[++cnt2]=abs(a);
			}
		}
		sort(y+1,y+cnt1+1);
		sort(x+1,x+cnt2+1);
		double ans,res;
		ans=0,res=0;
		for(int i=1;i<=n;i++)
		{
     
			ans+=sqrt(x[i]*x[i]+y[i]*y[i]);
		}
		printf("%.10lf\n",ans);
	}
	return 0;
 } 

D

D自己想没有想出来。这里贴一下别的大佬的思路


如果有最长路,那么最长路的个数不能>1。因为如果大于1,A先手,B走另外一条就可以赢。
然后我们就只要判断,最长路的点的左边与右边是否相等,如果相等并且是奇数,那么A赢。
如果不相等,后手的B只要构造,缩小长度变成偶数就可以赢。就是0

AC代码:
ps:这里顺便学了一下,用二维数组动态的存每个点所在升序序列和降序序列的长度。

//D. Let's Go Hiking
#include
using namespace std;
const int N=1e5+10;
typedef long long ll ;
ll n;
ll arr[N];
ll dp[N][2];
map<ll,ll> cnt1;
map<ll,ll> cnt2;
set<int> st;
int main()
{
     
	cin>>n;
	for(int i = 1;i<=n;++i)
    {
     
        scanf("%d",&arr[i]);
    }
    for(int i = 1;i<=n;++i)
    {
     
        if(i==1) dp[i][0] = 1;
        else
        {
     
            if(arr[i]>arr[i-1]) dp[i][0] = dp[i-1][0] + 1;
            else dp[i][0] = 1;
        }
    }
    for(int i = n;i>=1;--i)
    {
     
        if(i==n) dp[i][1] = 1;
        else
        {
     
            if(arr[i]>arr[i+1]) dp[i][1] = dp[i+1][1] + 1;
            else dp[i][1] = 1;
        }
    }
	ll maxx=0;
	for(int i=1;i<=n;i++)
	{
     
		maxx=max(maxx,max(dp[i][0],dp[i][1]));
	}
	for(int i=1;i<=n;i++)
	{
     
		if(dp[i][0]==maxx||dp[i][1]==maxx) st.insert(i);
	}
	if(st.size()>1)
	{
     
		cout<<"0"<<endl;
		return 0;
	}
	int xb=*st.begin();
	if((dp[xb][0]==dp[xb][1])&&(dp[xb][0]%2==1))
	{
     
		cout<<"1"<<endl;
		return 0; 
	}
	cout<<"0"<<endl;
	return 0;
}

你可能感兴趣的:(算法)