• bzoj3308 九月的咖啡店


    毒瘤结论题......

    题意:从1~n中选择若干个数,使得它们两两互质,且总和最大。

    求最大和。

    解:

    结论就是:对于每一个所选的数,至多包含两个质因子,且一个大于n0.5,一个小于等于n0.5

    然后还有一些附加的小结论,比如大于n0.5的b和小于n0.5的a如果要组合成一个数,那么b要尽量多。

    证明还不知道.....zzq有个解释:

    好,假设我们已经知道这个结论了。

    把所有质数分成两部分,n²连边,求最大费用即可。

    其中费用为"把这两个质因数合起来凑一个数比单独选这两个质因数多出来的值"。

    然后s->质因数->质因数->t,流量为1。

    求最大费用即可。

    其中连边的时候有些常数优化,可以减少枚举,减少连边。具体看代码。

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <queue>
      4 #include <cstring>
      5 #include <cmath>
      6 
      7 const int N = 18000, M = 1000010, INF = 0x3f3f3f3f;
      8 
      9 struct Edge {
     10     int nex, v, c, len;
     11 }edge[M << 1]; int top = 1;
     12 
     13 int e[N], d[N], vis[N], pre[N], flow[N], ot[N], p[200010], tp, n;
     14 std::queue<int> Q;
     15 bool vp[200010];
     16 
     17 inline void add(int x, int y, int z, int w) {
     18     top++;
     19     edge[top].v = y;
     20     edge[top].c = z;
     21     edge[top].len = w;
     22     edge[top].nex = e[x];
     23     e[x] = top;
     24 
     25     top++;
     26     edge[top].v = x;
     27     edge[top].c = 0;
     28     edge[top].len = -w;
     29     edge[top].nex = e[y];
     30     e[y] = top;
     31     return;
     32 }
     33 
     34 inline bool SPFA(int s, int t) {
     35     memset(d, 0x3f, sizeof(d));
     36     d[s] = 0;
     37     flow[s] = INF;
     38     vis[s] = 1;
     39     Q.push(s);
     40     while(!Q.empty()) {
     41         int x = Q.front();
     42         Q.pop();
     43         vis[x] = 0;
     44         for(int i = e[x]; i; i = edge[i].nex) {
     45             int y = edge[i].v;
     46             if(edge[i].c && d[y] > d[x] + edge[i].len) {
     47                 d[y] = d[x] + edge[i].len;
     48                 pre[y] = i;
     49                 flow[y] = std::min(flow[x], edge[i].c);
     50                 if(!vis[y]) {
     51                     vis[y] = 1;
     52                     Q.push(y);
     53                 }
     54             }
     55         }
     56     }
     57     return d[t] < INF;
     58 }
     59 
     60 inline void update(int s, int t) {
     61     int temp = flow[t];
     62     while(t != s) {
     63         int i = pre[t];
     64         edge[i].c -= temp;
     65         edge[i ^ 1].c += temp;
     66         t = edge[i ^ 1].v;
     67     }
     68     return;
     69 }
     70 
     71 inline int solve(int s, int t, int &cost) {
     72     int ans = 0;
     73     cost = 0;
     74     while(SPFA(s, t)) {
     75         if(d[t] > 0) {
     76             break;
     77         }
     78         ans += flow[t];
     79         cost += flow[t] * d[t];
     80         update(s, t);
     81     }
     82     return ans;
     83 }
     84 
     85 inline void getp(int b) {
     86     for(int i = 2; i <= b; i++) {
     87         if(!vp[i]) {
     88             p[++tp] = i;
     89         }
     90         for(int j = 1; j <= tp && p[j] * i <= b; j++) {
     91             vp[i * p[j]] = 1;
     92             if(i % p[j] == 0) {
     93                 break;
     94             }
     95         }
     96     }
     97     return;
     98 }
     99 
    100 inline int val(int i, int lm = n) {
    101     int ii = i;
    102     while(1ll * ii * i <= lm) {
    103         ii *= i;
    104     }
    105     return ii;
    106 }
    107 
    108 inline int Val(int i, int j) {
    109     return val(i) + val(j) - val(i, n / j) * j;
    110 }
    111 
    112 int main() {
    113 
    114     int ans = 0, m;
    115     scanf("%d", &n);
    116     getp(n);
    117     int s = N - 1, t = N - 2;
    118     int lm = (int)sqrt(n);
    119     for(int i = 1; i <= tp; i++) {
    120         if((p[i] << 1) > n) {
    121             ans += p[i];
    122             continue;
    123         }
    124         if(p[i] <= lm) {
    125             add(s, i, 1, 0);
    126             m = i;
    127         }
    128         else {
    129             add(i, t, 1, 0);
    130         }
    131         ans += val(p[i]);
    132     }
    133     for(int i = 1; i <= m; i++) {
    134         for(int j = m + 1; j <= tp; j++) {
    135             if(p[i] * p[j] <= n) {
    136                 add(i, j, 1, Val(p[i], p[j]));
    137             }
    138             else {
    139                 break;
    140             }
    141         }
    142     }
    143     int cost;
    144     solve(s, t, cost);
    145     printf("%d", ans - cost + 1);
    146     return 0;
    147 }
    AC代码
  • 相关阅读:
    luogu P3375 【模板】KMP字符串匹配
    leetcode[129]Sum Root to Leaf Numbers
    leetcode[130]Surrounded Regions
    leetcode[131]Palindrome Partitioning
    leetcode[132]Palindrome Partitioning II
    leetcode[133]Clone Graph
    leetcode[134]Gas Station
    leetcode[135]Candy
    leetcode[136]Single Number
    leetcode[137]Single Number II
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10103033.html
Copyright © 2020-2023  润新知