HDU 4610 Cards

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题目:每个数,有4个评估

1、是素数 2、约数个数是素数 3、约数的和是素数 4、约数的乘积是完全平方数

从n个中选出k个,使得分数最高,如果选的k个中没有一个满足某个条件,则有另外的分值

http://acm.hdu.edu.cn/showproblem.php?pid=4610

首先因为数据范围不大,1-1e6,可以预处理,用到的数是20000个

第一次把1e6的所有数的各项评估都完成,直接TLE,N * sqrt(N)的复杂度,其实用到的只有2W,不需要全部预处理,打好素数表就行了。

第一项直接利用素数表,2、3项枚举约数后利用素数表,第4项不能直接保存乘积再判断,可以发现sqrt(n)枚举约数的时候,每次两个约数 i , n / i 他们的乘积是n,所以约数乘积是n ^ y * (n 是平方数? sqrt(n) : 1) 。

所以可以边乘边化简。

处理完之后,对于所有的数,可以分为2 ^ 4类。

第一次做法是:枚举哪几种评估不选,然后 贪心,WA,对拍后发现问题,这样选可能某个评估的值还是没有选到,但是额外值没有加入,而额外值又可能是负的。

第二次:枚举2 ^ 16种情况,表现选哪几种,要注意的时候,枚举了哪几种,那么就至少要取一个,否则还是会出现上面的情况。之后还是贪心就行了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1000001;
const int M = 1005;
bool isprime[N << 2] = {false}, flag[N][4] = {false} , vis[N] = {false};
int score[N] = {0} , state[N];
int n , k , b[4] , cnt[1 << 4] , get[1 << 4] , id[1 << 4];
bool issquare (LL num) {
    LL t = sqrt(num + 0.0);
    if(t * t == num || (t + 1) * (t + 1) == num || (t - 1) * (t - 1) == num) return true;
    return false;
}
bool cmp (int a , int b) {
    return get[a] > get[b];
}
void Init() {
    for (int i = 0 ; i < N << 2; i ++) {
        isprime[i] = true;
    }
    isprime[1] = false;
    for (int i = 2 ; i < N << 2 ; i ++) {
        if (! isprime[i]) continue;
        for (int j = 2 ; i * j < N << 2 ; j ++) {
            isprime[i * j] = false;
        }
    }
    get[0] = 0;
    for (int i = 1 ; i < 1 << 4 ; i ++) {
        get[i] = get[i >> 1] + (i & 1);
    }
    for (int i = 0 ; i < 1 << 4 ; i ++) {
        id[i] = i;
    }
    sort (id , id + (1 << 4) , cmp);
}
void check(int i) {
    if (vis[i]) return ;
    flag[i][0] = isprime[i];
    int sum = 0 , cnt = 0;
    LL product = 1LL;
    for (int j = 1 ; j * j <= i ; j ++) {
        if(i % j == 0) {
            product = (LL)product * j;
            sum += j;
            cnt ++;
            if (j * j != i) {
                product *= i / j;
                sum += i / j;
                cnt ++;
            }
            if (product == (LL)i * i) {
                product = 1LL;
            }
        }
    }
    flag[i][1] = isprime[cnt];
    flag[i][2] = isprime[sum];
    flag[i][3] = issquare(product);
    for (int j = 0 ; j < 4 ; j ++) {
        score[i] += flag[i][j] ? 1 : 0;
        state[i] += (flag[i][j] ? 1 : 0) << j;
    }
    vis[i] = true;
}
int main () {
    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r" , stdin);
    #endif
    Init();
    int t;
    scanf ("%d", &t);
    while (t --) {
        scanf ("%d %d", &n, &k);
        for (int i = 0 ; i < 1 << 4; i ++) {
            cnt[i] = 0;
        }
        for (int i = 0 ; i < n ; i ++) {
            int a , b;
            scanf ("%d %d", &a, &b);
            check(a);
            cnt[state[a]] += b;
            printf("%d%c", score[a], i == n - 1 ? '\n' : ' ');
        }
        for (int i = 0 ; i < 4 ; i ++) {
            scanf ("%d", &b[i]);
        }
        int ans = - (1 << 20);
        for (int i = 0 ; i < 1 << 16 ; i ++) {
            int remain = k , ret = 0 , cur = 0;
            for (int j = 0 ; j < 1 << 4 ; j ++) {
                if(! (i & (1 << id[j]))) continue;
                if(cnt[id[j]]) {
                    remain --;
                    ret += get[id[j]];
                }
                else remain = -1;
            } 
            if (remain < 0) continue;
            for (int j = 0 ; j < 1 << 4 ; j ++) {
                if(! (i & (1 << id[j]))) continue;
                cur |= id[j];
                if(remain && remain > cnt[id[j]] - 1) {
                    remain -= cnt[id[j]] - 1;
                    ret += (cnt[id[j]] - 1) * get[id[j]];
                }
                else {
                    ret += remain * get[id[j]];
                    remain = 0;
                }
            }
            if (remain == 0) {
                for (int j = 0 ; j < 4 ; j ++) {
                    if(! ((1 << j) & cur) )
                        ret += b[j];
                }
                ans = max (ans , ret);
            }
        }
        printf ("%d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(HDU 4610 Cards)