转载请注明出处,谢谢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; }