T1
#题目描述 :
对于给定的一个正整数n, 判断n是否能分成若干个正整数之和 (可以重复) ,
其中每个正整数都能表示成两个质数乘积。
#输入描述:
第一行一个正整数 q,表示询问组数。
接下来 q 行,每行一个正整数 n,表示询问。
#输出描述:
q 行,每行一个正整数,为 0 或 1。0 表示不能,1 表示能。
#样例输入:
5
1
4
5
21
25
#样例输出:
0
1
0
1
1
#数据范围:
\(30\%\)的数据满足:\(q\leq20, n\leq20\)
\(60\%\)的数据满足:\(q\leq10000, n\leq5000\)
\(100\%\)的数据满足:\(q\leq10^5, n \leq 10^{18}\)
解题思路:
看到这个奇葩的数据范围,我先看到了\(100\%\)的\(n \leq 10^{18}\)
然后我就不知道怎么想的,写了一个不知道能不能跑过60分的完全背包?
code:
#include <bits/stdc++.h> #define N 5010 #define ll long long #define M 1010 #define _ 0 using namespace std; map<int, int> mp; bool vis[N], b[N]; int q, m, mx, mi = 99999999, cnt, tot; int po[10000100], f[N], qust[N << 1], prime[N]; int read() { int s = 0, f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar(); return f ? -s : s; } void erlur(int s) { for (int i = 2; i <= s; i++) { if (!vis[i]) prime[++cnt] = i; for (int j = 1; j <= cnt; j++) { if (i * prime[j] > s) break; vis[i * prime[j]] = 1; if (i % prime[j] == 0) break; } } } int main() { freopen("a.in", "r", stdin); // freopen("a.out", "w", stdout); q = read(); for (int i = 1; i <= q; i++) { qust[i] = read(); mx = max(mx, qust[i]); } erlur(mx); for (int i = 1; i <= cnt; i++) for (int j = 1; j <= cnt; j++) { int an = prime[i] * prime[j]; if (!mp[an] && an <= mx) mp[an] = 1, po[++tot] = an, mi = min(mi, an); } cout << tot << "\n"; for (int i = 1; i <= q; i++) { if (b[qust[i]]) cout << 1 << " "; else { memset(f, 0, sizeof(f)); int flag = 0; for (int j = 1; j <= tot; j++) for (int k = po[j]; k <= qust[i]; k++) { f[k] = max(f[k], f[k - po[j]] + po[j]); if (f[k] == qust[i]) flag = 1; } if (flag) b[qust[i]] = 1, puts("1"); else puts("0"); } } return 0; }
在打出来的时候尝试一下\(60\%\)的范围,结果发现自己的程序跑步过去,然后就把前\(1000\)个输了出来,然后发现除了前边的\(1,2,3,5,7,11\)之外所有的数都是1,只有这两个是0.
证明啊
当\(n \leq 20\) 时, 只有\(1,2,3,5,7,11\)无解,其余均有解。
当\(n > 20\) 时, 因为\(n = (n - 4) + 4 = (n-4) + 2 \ast 2\),而\((n-4)\)这个数\(\geq16\), 是一定有解的。
所以,我们证明了对于任意的正整数\(n\),只有\(n = 1,2,3,5,7,11\)时无解,其余均有解。
正解代码:
#include <bits/stdc++.h> #define N 100010 #define M 1010 #define _ 0 using namespace std; long long q, n; int read() { int s = 0, f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar(); return f ? -s : s; } int main() { freopen("a.in", "r", stdin); freopen("a.out", "w", stdout); q = read(); for (int i = 1; i <= q; i++) { n = read(); if (n == 1 || n == 2 || n == 3 || n == 5 || n == 7 || n == 11) puts("0"); else puts("1"); } return 0; }