Codeforce div3 579

A. Circle of Students

判断是否全是顺时针或者全是逆时针顺序。

不是第一个人或者最后一个人的时候,后一个人与前一个人之差要么为+1,要么为-1;如果是开头结尾则为n-1或者1-n。判断输入的第一个人和第二人之差,f=p[1]-p[0],如果f绝对值不为1,看f绝对值是否为n-1,都不是那肯定不对。

当f为n-1的时候,队列一定是逆时针,p[i]-p[i-1]=-1(i!=1&&i<n)

当f为1-n的时候,队列一定是顺时针,p[i]-p[i-1]=1.(i!=1&&i<n)

当f为-1的时候,队列一定是逆时针,p[i]-p[i-1]=-1.,存在1次n-1(i<n)

当f为1的时候,队列一定是顺时针,p[i]-p[i-1]=1.,存在1次1-n(i<n)

然后再去判断剩下所有人即可。注意n-1或1-n这种情况只会出现一次,剩下一定是1或-1

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
int p[205];
int main()
{
	int q,n,f=0;
	cin>>q;
	while(q--)
	{
		cin>>n;
		int cnt=0;
		bool flag=true;
		memset(p,0,sizeof(p));
		for(int i=0;i<n;i++)
			cin>>p[i];
		f=p[1]-p[0];
		if(f!=1&&f!=-1)
		{
			if(abs(f)!=n-1)
				flag=false;//绝对值不等于1或n-1一定错
			else
			{
				if(f>0)
					f=-1;
				else
					f=1;
			}
		}
		for(int i=1;i<n&&flag;i++)
		{
			if(p[i]-p[i-1]!=f)
			{
				if(abs(p[i]-p[i-1])==n-1&&(p[i]-p[i-1])*f<0&&cnt==0)//n-1对应-1,1-n对应n,相乘一定小于0
				{
					cnt=1;//出现过一次就不能再出现了
					continue;
				}
				else 
				{
					flag=false;
					break;
				}
			}
		}
		if(flag) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
}

B. Equal Rectangles

给你4*n条边,能否组成n个面积大小相同的矩形。

矩形只用考虑两条边即可。一定当前最大边和最小边结合。假设不是当前最小边和最大边(边长不重复)结合,那么最小边lmin和边l1(非最大边)结合得到面积s1的矩形,那么最大边lmax与边2(非最小边)结合得到面积为s2的矩形,

s1=lmin*l1

s2=lmax*l2

因为l1<lmax,lmin<l1

则s2>s1

所以排序后,每次让最大边和最小边结合即可。另外注意当前最小边前面的边大小一定等于最小边,最大边后面的一定要等于最大边,要不然构不成矩形。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
int s[405];
int main()
{
	int q,n;
	cin>>q;
	while(q--)
	{
		cin>>n;
		for(int i=0;i<4*n;i++)
			cin>>s[i];
		sort(s,s+4*n);
		int cnt=0,sm=s[0]*s[4*n-1];
		bool flag=true;
		for(int i=0;i<=2*(n-1);i+=2)
		{
			int last=4*n-1-i;
			if(s[i+1]!=s[i]||s[last]!=s[last-1]||s[i]*s[last]!=sm)
			{
				flag=false;
				break;
			}
		}
		if(flag) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
}

 C. Common Divisors

求能被当前所有数字整除的数的个数。

求最大公因数的因子数。gcd之后暴力求即可。注意这种涉及因子的问题,1要特判,完全平方数要特判。

经过zyy大佬的点拨,1不会进sqrt的循环,在完全平方数的时候会判断到它。

另外第一次写完全平方数的特判的时候,竟然用n%sqrt(n)==0来判,真是失了智。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#define LL long long
using namespace std;
LL q[400010];
LL gcd(LL a,LL b)
{
	if(b==0)
		return a;
	if(a<b)
		return gcd(b,a);
	return gcd(b,a%b);
}
int main()
{
	int n;
	cin>>n;
	LL g,num=0;
	for(int i=0;i<n;i++)
	{
		cin>>q[i];
		if(i==0)
			g=q[i];
		else
			g=gcd(g,q[i]);
	}
	if(g==1)//1的特判
		cout<<"1";
	else
	{
		for(LL i=1;i<sqrt(g);i++)
			if(g%i==0)
				num+=2;
		LL i=sqrt(g);//完全平方数特判
		if(i*i==g) num++;
		cout<<num;
	}
}

 D. Remove the Substring

这题我不知道暴力怎么写。。。当时直接跳了,其实已经有了想法,但我的想法是基于子字符序列的字母,而不是子字符序列,重复的时候无法还原子字符序列,觉得不可做,就跳了,最后发现自己弱智了,基于子子字符序列考虑,它的字母根本不重要。

找出子字符序列在母字符串第一次出现的的时候每一位的下标,和最后一次出现每一位的下标,删除的话只能删除第一个字母之前,两个相邻字母之间,最后一个字母之后这三种情况。

举个例子

 012345678910111213141516171819
 kaskjdgajksagd      
 asd                 
第一次出现的位置 as  d              
最后一次出现的位置       a  s  d      

删除头的情况,最后一次出现asd的时候,a的下标是7,代表从头删的时候,这个地方的a不能删,否则无法构成asd了。注意不是最后一次出现a的11位置,要保证可以组成asd。那么7前面的都可以删。

删除尾的情况,第一次出现asd的d是在5,代表从尾删的时候,这个位置的d不能删,否则就无法构成asd了。

在中间删除的情况,比如删除sd中间,那最大值就是s第一次出现与d最后一次出现之间的长度,再往前或往后延伸就构不成asd了。

所以从后往前扫一遍母串,找到子序列各位在母串最后一次出现的位置,再从前往后扫一遍,找到第一次出现的位置。然后维护最大值即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <string>
#include <vector>
#define LL long long
using namespace std;
int fp[200010],lp[200010];//fp是第一次出现的时候,lp是最后一次出现的时候
bool f[30];
int main()
{
	string s1,s2;
	cin>>s1>>s2;
	int l1=s1.size(),l2=s2.size();
	int cnt=l2-1;
	for(int i=l1-1;i>=0&&cnt>=0;i--)
	{
		if(s1[i]==s2[cnt])
			lp[cnt--]=i;//找到了后一位就开始找前一位
	}
	cnt=0;
	for(int i=0;i<l1&&cnt<l2;i++)
		if(s1[i]==s2[cnt])
			fp[cnt++]=i;
	int maxn=lp[0];
	for(int i=1;i<=l2-1;i++)
		maxn=max(maxn,lp[i]-fp[i-1]-1);
	maxn=max(maxn,l1-1-fp[l2-1]);
	cout<<maxn<<endl;
}

E. Boxers

每个数可以加一或减一,但不能为0,问你不同的数最多有多少个。

每个数只能出现出现一次,那就看一下这个数+1,不变,-1的数字有没有出现过,没有就可以把他加上,而且一个数只能出现一次,所以谁去当这个数都是无所谓的。

但是注意比较的顺序!!!对于n,先看n+1出现过没有,再看n,最后看n-1。

比如4 4 4 5

就可以让5变成6,然后4变成5,4不变,4变成3,将它们都放进队列。因此WA了一发,哭死。

“谁去当这个数都是无所谓的”意思是

比如3 4 4 4

可以让4变成5,4不变,4变成3进队列,而不要3;和将4变成5,4不变,3不变放进队列是一样的。只要3,4,5这三个数有人即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#define LL long long
using namespace std;
int w[150010],num[150010];
int main()
{
	int n,cnt=0;
	cin>>n;
	memset(w,0,sizeof(w));
	for(int i=0;i<n;i++)
		cin>>w[i];
	sort(w,w+n);
	for(int i=n-1;i>=0;i--)
	{
		if(num[w[i]+1]==0)
			num[w[i]+1]++,cnt++;
		else if(num[w[i]]==0)
			num[w[i]]++,cnt++;
		else if(w[i]-1!=0&&num[w[i]-1]==0)
			num[w[i]-1]++,cnt++;
	}	
	cout<<cnt<<endl;
}

总结:1、不要太急,想清楚了再写。

           2、做专题做的脑子有点死,适当做些思维题活跃一下脑子。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值