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代码

 

posted @ 2018-12-11 16:28  huyufeifei  阅读(...)  评论(...编辑  收藏