P1618 三連擊(升級版)

胖柚の工作室發表於2024-04-01

題目連結:

#include <bits/stdc++.h>

using namespace std;

int p[10], sum;
int main()
{
	int A, B, C;
	bool flag = false;
	scanf("%d%d%d", &A, &B, &C);
	for (int i = 1; i <= 999 / C; i++) {
		memset(p, 0, sizeof p);
		sum = 0;
		int a = A * i, b = B * i, c = C * i;
		int a1 = a % 10, a2 = (a / 10) % 10, a3 = (a / 100) % 10;
		int b1 = b % 10, b2 = (b / 10) % 10, b3 = (b / 100) % 10;
		int c1 = c % 10, c2 = (c / 10) % 10, c3 = (c / 100) % 10;
		p[a1] = p[a2] = p[a3] = p[b1] = p[b2] = p[b3] = p[c1] = p[c2] = p[c3] = 1;
		for (int i = 1; i <= 9; i++) sum += p[i];
		if (sum == 9) {
			printf("%d %d %d", a, b, c);
			flag = true;
			puts("");
		}
	}
	if (!flag) puts("No!!!");
	return 0;
}

值得一提的是,之所以用 \(A*i、B*i、C*i\) 而不是列舉第一個數 \(x\) 再去計算 \(B / A * x\)\(C / A * x\),是因為若 \(A=0\) 處理起來會比較麻煩,同時 \(B / A\)\(C / A\) 會導致精度不夠的問題,因此換乘為除。

需要注意的是,本題一開始還有另外一個 \(AC\) 程式碼:

#include <cstdio>
#include <set>

int main()
{
	int A, B, C;
	std::set<int> s;
	bool flag = false;
	scanf("%d%d%d", &A, &B, &C);
	for (int i = 1; i <= 999 / C; i++) {
		if (A != 0) {
			s.clear();
			int a = A * i, b = B * i, c = C * i;
			int a1 = a % 10, a2 = (a / 10) % 10, a3 = (a / 100) % 10;
			int b1 = b % 10, b2 = (b / 10) % 10, b3 = (b / 100) % 10;
			int c1 = c % 10, c2 = (c / 10) % 10, c3 = (c / 100) % 10;
			s.insert(a1);
			s.insert(a2);
			s.insert(a3);
			s.insert(b1);
			s.insert(b2);
			s.insert(b3);
			s.insert(c1);
			s.insert(c2);
			s.insert(c3);
			if (s.size() == 9 && a1 + a2 + a3 + b1 + b2 + b3 + c1 + c2 + c3 == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 && a1 * a2 * a3 * b1 * b2 * b3 * c1 * c2 * c3 == 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9) {
				printf("%d %d %d", a, b, c);
				flag = true;
				puts("");
			}
		}
		else {
			puts("No!!!");
			return 0;
		}	
	}
	if (!flag) puts("No!!!");
	return 0;
}

其利用的數學知識為:在集合元素個數相同的情況下,若兩個集合中的所有元素之和、之積均相等,則這兩個集合相等

但這個原理在某些情況下不滿足,比如 \((-4, 0, 4)\)\((-5, 0, 5)\)\((0, 1, 2)\)\((0, 3)\)。所以只當沒有辦法的時候可以考慮用這個定理來騙分。

相關文章