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;
}

 

posted @ 2017-11-23 21:22  zbtrs  阅读(446)  评论(0编辑  收藏  举报