cf 1886A

题目是输入一个数字,分解成三个数字的和,这三个数字都不相同,并且都不可以被三整除,如果存在输出YES并且输出任意一组可能的三个数字,否则输出NO

代码

#include
using namespace std;

int main()
{
	int t;
	scanf("%d",&t);
	
	while(t--)
	{
		int x,y,z;
		int n;
		bool flag=false;
		scanf("%d",&n);
		
		for(x=1;x<=10;x++)
		{
			for(y=x+1;y<=10;y++)
			{
				z=n-x-y;
				if(x%3!=0&&y%3!=0&&z%3!=0&&z>y)
				{
					printf("YES\n%d %d %d\n",x,y,z);
					flag=true;
					break;
				}
			}
			if(flag==true)	break;
		}
		if(!flag)	printf("NO\n");
	}
	
	return 0;
}

循环,让第二个数字y等于x+1就可以保证最开始两个数字就不相等,还是这种方法最明了,直接条件判断 

赛时代码

#include
using namespace std;
 
int ans[5];
 
int main()
{
	int t;
	scanf("%d",&t);
	
	while(t--)
	{
		int n;
		bool flag=false;
		scanf("%d",&n);
		int temp=n/3;
		
		if(n%3==0)
		{
			if(temp%3!=0)
			{
				ans[0]=temp-1,ans[1]=temp,ans[2]=temp+1;
				while((ans[0]%3==0||ans[2]%3==0)&&ans[0]>0)
				{
					ans[0]-=1;
					ans[2]+=1;
				}
			}
			else
			{
				ans[0]=temp,ans[1]=temp-1,ans[2]=temp+1;
				while((ans[0]%3==0||ans[2]%3==0||ans[0]==ans[1])&&ans[0]>0)
				{
					ans[0]-=1;
					ans[2]+=1;
				}
			}
			
			if(ans[0]+ans[1]+ans[2]==n&&ans[0]%3!=0&&ans[2]%3!=0&&ans[1]%3!=0&&ans[0]!=ans[1]&&ans[0]!=ans[2]&&ans[1]!=ans[2])	flag=true;
		}
		else
		{
			int q=n%3;
			ans[0]=temp,ans[1]=temp,ans[2]=temp+q;
			if(temp%3!=0)
			{
				ans[0]=temp,ans[1]=temp,ans[2]=temp+q;
				while((ans[0]%3==0||ans[2]%3==0||ans[0]==ans[1])&&ans[0]>0)
				{
					ans[0]-=1;
					ans[2]+=1;
				}
			}
			else
			{
				ans[0]=temp-1,ans[1]=temp+1,ans[2]=temp+q;
				while((ans[0]%3==0||ans[2]%3==0||ans[0]==ans[1]||ans[1]==ans[2])&&ans[0]>0)
				{
					ans[0]-=1;
					ans[2]+=1;
				}
			}
			
			if(ans[0]+ans[1]+ans[2]==n&&ans[0]%3!=0&&ans[2]%3!=0&&ans[1]%3!=0&&ans[0]!=ans[1]&&ans[0]!=ans[2]&&ans[1]!=ans[2])	flag=true;
		}
		
		if(n<=3)	flag=false;
		
		if(flag==true)	
		{
			printf("YES\n");
			printf("%d %d %d\n",ans[0],ans[1],ans[2]);
		}
		else	printf("NO\n");
	}
	
	return 0;
}

标签是暴力破解,构造算法,数学

仔细想了一下,确实暴力就可以直接过

我比赛的时候想的方法确实比较繁琐哈哈

讨论输入的数字n是否能够被3整除,把数字n除以3,然后把这三个数字放在ans[0],ans[1],ans[2]里面,保证中间的位置满足不被3整除,然后调整ans[0],ans[2]这两个数字,ans[0]--,ans[2]++,一个因子减少一,另一个因子增加一,和n保持不变,所以可以满足条件,也可以寻找到答案

 另外一种解法

#include
using namespace std;

int main()
{
	int t;
	scanf("%d",&t);
	
	while(t--)
	{
		int n;
		scanf("%d",&n);
		if(n%3==0)
		{
			int z=n-5;
			if(z%3!=0&&z>4)	printf("YES\n1 4 %d\n",z);
			else	printf("NO\n");
		}
		else
		{
			int ans=n-3;
			if(ans%3!=0&&ans>2)	printf("YES\n1 2 %d\n",ans);
			else	printf("NO\n");
		}
	}
	
	return 0;
}

上面这种做法是找规律,我们只需要输出一种符合条件的情况即可,所以我们考虑一些特殊的数字,比如说1和2,这两个数字不相同并且两个数字的和是3,如果数字n是可以被3整除的,并且大于3的话(如果是3的话,剩下的那个数字只可以是0,不符合条件),剩下的那个数字就一定可以被3整除,但是如果n不可以被3整除,剩下的那个数也不可以被3整除(如果可以被3整除的话,n就可以被3整除了)

有点绕

分两种特殊情况来考虑,第一种特殊情况,取x=1,y=2,这个时候假设n是不能被3整除的数字,剩下的那个数字我们记为z,z一定是不能被3整除的,因为假设z可以被3整除,加上3还是可以被3整除(加上3就等于n了),和假设矛盾,所以z一定不能被3整除(反证法),注意需要满足z大于2这个条件

第二种情况就是取x=1,y=4,考虑n可以被3整除,剩下的数字z一定是不可以被3整除的,证明如下,还是反证法,就是假设z是可以被3整除的,假设z=3b,n=3k,那么有5+3b=3k,移向可以得到5/3=k-b,两个整数的差不可能是小数,所以矛盾,所以z一定是不可以被3整除的

#include
using namespace std;

int main()
{
	int t;
	scanf("%d",&t);
	
	while(t--)
	{
		int n;
		scanf("%d",&n);
		if(n%3==0)
		{
			int z=n-5;
			if(z>4)	printf("YES\n1 4 %d\n",z);
			else	printf("NO\n");
		}
		else
		{
			int ans=n-3;
			if(ans>2)	printf("YES\n1 2 %d\n",ans);
			else	printf("NO\n");
		}
	}
	
	return 0;
}

经过一通分析之后发现这样子其实更加简洁,但是前期需要分析的更多一些

 

 

 

你可能感兴趣的:(算法竞赛,算法,c++,开发语言)