vijos 小三学算术
描述
小三的三分球总是很准的,但对于数学问题就完全没有想法了,他希望你来帮他解决下面的这个问题:对于给定的n,从1!、2!、3!、……、n!中至少删去几个数,才可以使剩下的数的乘积为完全平方数?
格式
输入格式
仅一行,包含一个整数n(1≤n≤500)。
输出格式
第一行包含一个整数k,表示最少需要删去的数字个数。
接下来一行,从小到大排列的k个[1,n]之间的整数,给出删数的方案。如果方案不止一种,输出方案从小到大排序序列最小的一组即可。
样例1
样例输入1
5
样例输出1
2
2 5
限制
各个测试点1s
提示
样例说明:去掉2!和5!,剩下的是4!、3!和1!,它们的乘积为4!×3!×1!=24×6=144。
分析:数学一本通上一本非常神的题.先对每个数分解质因数,如果一个数是完全数,那么它的所有质因子的次数一定要是偶数,这样的话很难操作,没有什么特别好的方法.尝试搜索,因为不知道要删掉几个数,可以用迭代深搜,可能会惊奇地发现自己过了,因为这道题有一个结论:答案不超过3.
先把阶乘两两分组,(1*2!)*(3!*4!)*(5!*6!)......每一组前面的数会被后面的数所覆盖,这些数的质因子的次数一定是偶数,那么把每一组对答案有影响的数给提出来:2*4*6*......再提一个2出来:
2*(1*2*3*......)=2!*(n/2)!那么删掉这两个阶乘就好了.这是n为偶数的情况,如果n为奇数,那么就把最后单独的那一个给删掉,然后就变成了偶数的情况,所以最多删3个数.
奇偶性的转换可以利用异或运算来实现.不过代码有缺陷,质因子个数可能会大于300.自己改不动了......
#include <cstdio> #include <cmath> #include <map> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; ll n, maxn, use[510], prime[510], vis[510], tot, sta[510], tsta, staa[510]; ll num[50], ans[50]; bool flag = false; //位运算 void dfs(ll dep, ll maxx, ll nowsta, ll num) { if (dep == n + 1 || num == maxx + 1) { if (nowsta == 0) { for (ll i = 1; i <= maxx; i++) ans[i] = use[i]; flag = 1; } return; } ll temp = nowsta ^ sta[dep]; dfs(dep + 1, maxx, nowsta, num); use[num] = dep; dfs(dep + 1, maxx, temp, num + 1); } void init() { for (ll i = 2; i <= 500; i++) { if (!vis[i]) prime[++tot] = i; for (ll j = 1; j <= tot; j++) { ll t = prime[j] * i; if (t > 500) break; vis[t] = 1; if (i % prime[j] == 0) break; } } } int main() { init(); scanf("%lld", &n); for (ll i = 1; i <= n; i++) { ll x = i; for (ll j = 1; j <= 64; j++) { ll p = 0; while (x && x % prime[j] == 0) { x /= prime[j]; p = (p + 1) % 2; } if (p == 1) staa[i] |= (1LL << (j - 1)); } } memcpy(sta, staa, sizeof(staa)); for (ll i = 1; i <= n; i++) for (ll j = 1; j < i; j++) sta[i] ^= staa[j]; for (ll i = 1; i <= n; i++) { if (i == 1) tsta = sta[i]; else tsta ^= sta[i]; } while (1) { maxn++; memset(use, 0, sizeof(use)); dfs(1, maxn, tsta, 1); if (flag) { printf("%lld\n", maxn); for (int i = 1; i <= maxn; i++) printf("%lld ", ans[i]); break; } } return 0; }