毒瘤結論題......ide
題意:從1~n中選擇若干個數,使得它們兩兩互質,且總和最大。優化
求最大和。spa
解:code
結論就是:對於每個所選的數,至多包含兩個質因子,且一個大於n0.5,一個小於等於n0.5blog
而後還有一些附加的小結論,好比大於n0.5的b和小於n0.5的a若是要組合成一個數,那麼b要儘可能多。get
證實還不知道.....zzq有個解釋:string
好,假設咱們已經知道這個結論了。it
把全部質數分紅兩部分,n²連邊,求最大費用便可。io
其中費用爲"把這兩個質因數合起來湊一個數比單獨選這兩個質因數多出來的值"。event
而後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 }