Codeforces Round #829 (Div. 2)

感觉这场div2比较简单,就是考试的时候B题卡的时间太长了,导致后面的题也没心情看,结束后看才发现很简单,可以轻轻松松的解出来,也没有涉及什么算法知识。

 

 

 

A题的意思是给定只包含Q,A的字符串,询问是否可以匹配所有的回答。需要注意的一个点就是假如A之前没有Q,则这个A没有任何的意义。整体的思路像栈的操作一样。Q进栈,遇到A的话,只要不空栈就出栈,只至为空。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,t;
	cin >> n;
	while (n--)
	{
		cin >> t;
		string s;cin >> s;
		int q = 0,a = 0;
		int flag = 0;
		for (int i = 0;i<t;i++)
		{
			if (s[i] == 'Q')
			{
				q++;	
			 } 
			else if (s[i]== 'A')
			{
				if (q!=0) q--; 
			}
		}
		
		if (q==0) cout << "Yes"<<"\n";
		else cout <<"No"<<"\n";
	 } 
	return 0;
 } 

 B题的意思就是自己排列1到n这n个数字,而且取出相邻的两个数字的绝对差值的最小值,并保证这个最小值要最大。刚开始的思路比较乱,在那里乱画,乱举例。其实这类题基本上就是分成几个有顺序的数组,然后进行组合。比如n为12,可以分为两个数组1 2 3 4 5 6和 7 8 9 10 11 12,然后组成一个完整的数组7 1 8 2 9 3 10 4 11 5 12 6,像这样交叉组合,可以保证这个的最大值为6.如果为奇数,可以在最前面加上一个n即可。这个思想感觉有点妙,两两配对,让他们的差值均为n/2.

#include<bits/stdc++.h>
using namespace std;
int a[1006],b[1006];
int main()
{
	int n,t;cin >> n;
	while (n--)
	{
		cin >> t;
		int mn = t/2;//得出的最小数
		for (int i = 1;i<=mn;i++)
		{
			a[i] = i;
			b[i] = i+mn;
		}
		if (t&1) cout << t<<" ";
		for (int i = 1;i<=mn;i++)
		{
			cout << b[i] <<" " << a[i] <<" ";
		}
	}
	return 0;
 } 

 

 C1题的意思就是给定一串长度为n的-1,1串,再给定一个规则划分区间,使得区间里面的数字+ -交换操作,得到区间的和,然后所有区间的和是否可以等于0。其实进行简单分析一下就可以得出,假如数字的个数是奇数,那无论怎么配对都不可能成功,直接输出-1,假如个数为偶数,则一定会成功,具体的推理的话,可以分成两两一队,而这一对只有四种可能1 1,1 -1 ,-1 -1 ,-1 1.

这四种可能都可以独立进行划分得到结果0,因此最后的结果也一定可以为0.但是我的方法和这个不是完全一致,应该说有些升级吧。就是我先判断所有的数字总和,假如和为0,那我不需要操作任何数字,每一个数字都是单独的区间,这样就可以满足条件。假如和为2,那说明1这个数字过多,所以要消除一些1,因此,只要把1放在第二位也就是变成-1,这样整体的值就会减少2,其他的再单独区间输出即可。负数也类似。这样的话需要输出的区间个数也比较好算n-(多的部分)+(多的部分)/ 2 = n-(多的部分)/ 2。

#include<bits/stdc++.h>
using namespace std;
int num[200006];//存储数组列表
int main()
{
	int n,k;cin >> n;
	while (n--)
	{
		cin >> k;
		int sum = 0;//求和
		for (int i = 1;i<=k;i++)
		{
			int x;
			cin >> x;
			num[i]=x;
			sum+=x;
		}
		if (k&1)//奇数直接跳出此次
		{
			cout << "-1\n";
			continue;
		 } 
		int flag = 1;//为正数 
		if (sum<0) flag= 0; 
		int t = abs(sum)/2;
		int h = 0; 
		cout << k-t<<"\n";
		for (int i = 1;i<=k;i++)
		{
			if(flag)//正数多 需要消除  两两小 
			{
				if(num[i+1]==1 && i+1<=k && h!=t) //还需要判断达到t组就结束了
				{
					cout << i << " " << i+1 <<"\n";
					h++;
					i++;
		
				}else cout<<  i << " " << i <<"\n";
			}else 
			{
				if(num[i+1]==-1 && i+1<=k && h!=t) 
				{
					cout << i << " " << i+1 <<"\n";
					h++;
					i++;
				}else cout << i << " " << i <<"\n";
			}
		}
		
	}
	return 0;
 } 

C2题的话,就是数组里面的数字增加了一个0,然后还是判断最后的区间和是否可以为0。样例稍微有点不一样。

 解决的方法和上面的可以说是一致的,还是先加上所有的数字判断和。假如和为奇数,则必然不可能,为偶数,则必然可以。然后下面的分析也就一致了,得出其偏离的程度,然后再划分区间。

#include<bits/stdc++.h>
using namespace std;
int num[200006];
int main()
{
	int n,k;cin >> n;
	while (n--)
	{
		cin >> k;
		int sum = 0;
		for (int i = 1;i<=k;i++)
		{
			int x;
			cin >> x;
			num[i]=x;
			sum+=x;
		}
		int flag = 1;//为正数 
		if (sum<0) flag= 0; 
		if (sum&1) //唯一改变的地方
		{
			cout <<"-1\n";
			continue;
		}
		int t = abs(sum)/2;
		int h = 0; 
		cout << k-t<<"\n";
		for (int i = 1;i<=k;i++)
		{
			if(flag)//正数多 需要消除  两两小 
			{
				if(num[i+1]==1 && i+1<=k && h!=t) 
				{
					cout << i << " " << i+1 <<"\n";
					h++;
					i++;
		
				}else cout<<  i << " " << i <<"\n";
			}else 
			{
				if(num[i+1]==-1 && i+1<=k && h!=t) 
				{
					cout << i << " " << i+1 <<"\n";
					h++;
					i++;
				}else cout << i << " " << i <<"\n";
			}
		}
		
	}
	return 0;
 } 

 

 D题的意思就是下面的所有数字的阶乘和是否可以整除上面的x的阶乘,也很简单就两个结论。

1.  n! = (n-1)! * n .这就涉及到了进化理论 低层次的可以逐步进化到高阶段

2.  n! /(n-1)! = k 高段位阶乘可以整除比他小的段位阶乘,因此相当于最后进化的那个阶乘要大于x!

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n,x;cin >> n >> x;
	map<int,int> mp;
	int flag = 0;
	while (n--)
	{
		int t;cin >> t;
		if (mp.count(t)==0)
		{
			mp[t] = 1;
		}else mp[t]++;
		//统计每个数字出现的频率 准备进化 	
	}
     for(int i = 1;i<x;i++)
	{
		int temp = mp[i]/(i+1);//可以进化的次数 
		if (mp[i] != temp * (i+1)) flag = 1;
		
		if (mp.count(i+1)==0)
		{
			mp[i+1] = temp;
		}else mp[i+1]+=temp;
	}	

	if(flag) cout <<"No";
	else cout <<"Yes";
	return 0;
}

总结一下就是,读题太慢,搞不太明白,要不然可以快好多。 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值