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 }