hdu 4610 Cards(暴力+miller-rabin)

来源:互联网 发布:琵琶 知乎 编辑:程序博客网 时间:2024/06/09 15:22

题目链接:hdu 4610 Cards

解题思路

用素数筛选法先预处理出每个数的因子个数,因子和。因子个数肯定小于1e6,可以根据预处理的素数表直接判断是否为素数,但是因子和可能到达4百多万,所以直接用miller-rabin直接判素数。

判断因子积是否是平方和的部分,考虑因子个数,如果因子个数为奇数(即该数为平方数),则sqrt(i)必须是平方数才行。如果因子个数为偶数,则cnt/2为偶数时该数的因子积为平方数。

最后枚举一下哪些条件要满足,注意这里,因为有的条件附加值为负数。如果只枚举24状态,可能会有选取k个数后,同样满足附加为负数的条件。

代码

#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <ctime>#include <algorithm>using namespace std;const int maxn = 1e6;const int maxm = 1e3 + 5;const int mod = 1e9 + 7;const int inf = 0x3f3f3f3f;typedef long long ll;int cnt[maxn+5], sum[maxn+5], vis[maxn+5], val[20];ll pow_mod(ll x, int n, ll mod) {    ll ret = 1;    while (n) {        if (n&1) ret = ret * x % mod;        x = x * x % mod;        n >>= 1;    }    return ret;}bool miller_rabin(int n) {    if (n <= maxn) return vis[n];    srand(time(0));    for (int i = 0; i < 10; i++)        if (pow_mod(rand() % (n-1) + 1, n-1, n) != 1)            return false;    return true;}void presolve() {    vis[1] = 1;    for (int i = 2; i <= maxn; i++) {        cnt[i]++, sum[i] += i;        for (int j = i + i; j <= maxn; j += i) {            cnt[j]++;            sum[j] += i;            vis[j] = 1;        }    }    for (int i = 1; i <= maxn; i++) {        vis[i] = 1^vis[i];        cnt[i]++, sum[i]++;    }    val[0] = 0;    for (int i = 1; i < 16; i++)        val[i] = val[i>>1] + (i&1);}bool judge (int s) {    if (cnt[s]&1) {        s = (int)sqrt(s);        return cnt[s]&1;    }    return ((cnt[s]>>1)&1) == 0;}int N, K, C[20], extra[10];int getstatus(int x) {    int s = 0;    if (vis[x]) s |= 1;    if (vis[cnt[x]]) s |= 2;    if (miller_rabin(sum[x])) s |= 4;    if (judge(x)) s |= 8;    return s;}void init () {    int a, b;    scanf("%d%d", &N, &K);    memset(C, 0, sizeof(C));    for (int i = 1; i <= N; i++) {        scanf("%d%d", &a, &b);        int s = getstatus(a);        C[s] += b;        printf("%d%c", val[s], i == N ? '\n' : ' ');    }    for (int i = 0; i < 4; i++)        scanf("%d\n", &extra[i]);}int solve () {    int ret = -inf, c[10];    for (int i = 0; i < (1<<16); i++) {        int n = K, s = 0, g = 0;        memset(c, 0, sizeof(c));        for (int j = 0; j < 16; j++) {            if ((i&(1<<j)) == 0) continue;            if (C[j]) {                s |= j;                n--;                g += val[j];                c[val[j]] += C[j]-1;            } else                n = -1;        }        if (n < 0) continue;        for (int j = 4; j >= 0; j--) {            int tmp = min(n, c[j]);            g += tmp * j;            n -= tmp;        }        if (n) continue;        for (int j = 0; j < 4; j++) {            if ((s&(1<<j)) == 0)                g += extra[j];        }        ret = max(ret, g);    }    return ret;}int main () {    presolve();    int cas;    scanf("%d", &cas);    while (cas--) {        init();        printf("%d\n", solve());    }    return 0;}
0 0
原创粉丝点击