CF1692F 3SUM - 题解

方法 1:暴力

用三层循环枚举每一种 \(i,j,k\) 的选择。

时间复杂度 \(O(T \times N^3)\),因为 $ 3 \leq n \leq 2 \cdot 10^5 $,所以明显不可取。

代码就不用了,因为我也没用暴力。

方法 2 根据 \(a\) 的个位来枚举

\(a_i,a_j,a_k\) 之和的个位,只取决于这三个数的个位。

即:如果这三个数的个位的和的个位为 \(3\),那么这三个数的和的个位必定为 \(3\)

我们可以用 \(sum\) 记录每 \(a\) 数组内个个位数出现的次数,判断时把 \(sum_i,sum_j,sum_k\) 都减 \(1\),判断所有元素的出现次数(\(0 \sim 9\)),然后再判定能否在这些个位里面选三个,使得它们的和的个位为 \(3\),然后再加回去。

注意事项:

  • 即便是个位相加,它们的和依然可能是两位数,所以还需要再 \(\bmod 10\) 一次。

  • 不能只记录是否出现,例如 \(1\)\(0\) 各出现一次,那么程序会判断 \(1,1,1\) 的组合是合法的,但这实际上不合法。

上代码:

#include<cstdio>
#include<cstring>
using namespace std;

int T;
int n;
int sum[15];

int read()	//快读 
{
	int x=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*w;
}
int main()
{
	scanf("%d",&T);
	for(int I=1;I<=T;I++)
	{
		n=read();
		memset(sum,0,sizeof(sum));
		for(int i=1;i<=n;i++)
		{
			int a=read();	//没有必要用数组来存 
			sum[a%10]++;	//sum 记录每个个位出现的次数 
		}
		bool ans=false;
		for(int i=0;i<=9&&!ans;i++)		//!ans 使得找到方案马上退出 
			for(int j=0;j<=9&&!ans;j++)
				for(int k=1;k<=9&&!ans;k++)
				{
					sum[i]--,sum[j]--,sum[k]--;
					if((i+j+k)%10==3&&(sum[i]>=0&&sum[j]>=0&&sum[k]>=0))
						ans=true;
					sum[i]++,sum[j]++,sum[k]++;
				}
		printf("%s\n",ans?"YES":"NO");
	}
	return 0;
}

方法 3:打表出奇迹

我们可以发现,某些固定的三个个位的组合是合法的,那么我们为什么不事先枚举出所有的组合,然后再看数据是否符合条件呢?

核心代码:

int s[100][5]={			//s 代表所有可能的组合情况
	{0,0,3},{0,1,2},{0,2,1},{0,4,9},{0,5,8},{0,6,7},{0,7,6},{0,8,5},{0,9,4},
	{1,0,2},{1,1,1},{1,3,9},{1,4,8},{1,5,7},{1,6,6},{1,7,5},{1,8,4},{1,9,3},
	{2,0,1},{2,2,9},{2,3,8},{2,4,7},{2,5,6},{2,6,5},{2,7,4},{2,8,3},{2,9,2},
	{3,1,9},{3,2,8},{3,3,7},{3,4,6},{3,5,5},{3,6,4},{3,7,3},{3,8,2},{3,9,1},
	{4,0,9},{4,1,8},{4,2,7},{4,3,6},{4,4,5},{4,5,4},{4,6,3},{4,7,2},{4,8,1},
	{5,0,8},{5,1,7},{5,2,6},{5,3,5},{5,4,4},{5,5,3},{5,6,2},{5,7,1},{5,9,9},
	{6,0,7},{6,1,6},{6,2,5},{6,3,4},{6,4,3},{6,5,2},{6,6,1},{6,8,9},{6,9,8},
	{7,0,6},{7,1,5},{7,2,4},{7,3,3},{7,4,2},{7,5,1},{7,7,9},{7,8,8},{7,9,7},
	{8,0,5},{8,1,4},{8,2,3},{8,3,2},{8,4,1},{8,6,9},{8,7,8},{8,8,7},{8,9,6},
	{9,0,4},{9,1,3},{9,2,2},{9,3,1},{9,5,9},{9,6,8},{9,7,7},{9,8,6},{9,9,5}
};

for(int i=0;i<90&&!ans;i++)
{
	sum[s[i][0]]--,sum[s[i][1]]--,sum[s[i][2]]--;
	if(sum[s[i][0]]>=0&&sum[s[i][1]]>=0&&sum[s[i][2]]>=0)
		ans=true;
	sum[s[i][0]]++,sum[s[i][1]]++,sum[s[i][2]]++;
}

附上打表程序:

for(int i=0;i<=9;i++)
	{
		for(int j=0;j<=9;j++)
			for(int k=1;k<=9;k++)
				if((i+j+k)%10==3)		//如果满足条件则输出
					printf("{%d,%d,%d},",i,j,k);
		printf("\n");
	}

2022-07-20 15:48 撰写于洛谷,2025-08-29 20:28 迁移至博客园。

posted @ 2025-08-29 20:30  Jerrycyx  阅读(8)  评论(0)    收藏  举报