3275: Number
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 874 Solved: 371
[Submit][Status][Discuss]
Description
有N个正整数,需要从中选出一些数,使这些数的和最大。
若两个数a,b同时满足以下条件,则a,b不能同时被选
1:存在正整数C,使a*a+b*b=c*c
2:gcd(a,b)=1
Input
第一行一个正整数n,表示数的个数。
第二行n个正整数a1,a2,?an。
Output
最大的和。
Sample Input
5
3 4 5 6 7
3 4 5 6 7
Sample Output
22
HINT
n<=3000。
Source
机制建图,同 BZOJ 3158: 千钧一发 。
#include <cmath>
#include <cstdio>
#include <cstring> typedef long long lnt; const int siz = ;
const int inf = ; int n;
int a[siz];
int b[siz]; int tot;
int s, t;
int hd[siz];
int to[siz];
int fl[siz];
int nt[siz]; inline void add(int u, int v, int f)
{
nt[tot] = hd[u]; to[tot] = v; fl[tot] = f; hd[u] = tot++;
nt[tot] = hd[v]; to[tot] = u; fl[tot] = ; hd[v] = tot++;
} int dep[siz]; inline bool bfs(void)
{
static int que[siz];
static int head, tail; memset(dep, , sizeof(dep));
head = , tail = ;
que[tail++] = s;
dep[s] = ; while (head != tail)
{
int u = que[head++], v; for (int i = hd[u]; ~i; i = nt[i])
if (!dep[v = to[i]] && fl[i])
dep[que[tail++] = v] = dep[u] + ;
} return dep[t];
} int cur[siz]; int min(int a, int b)
{
return a < b ? a : b;
} int dfs(int u, int f)
{
if (u == t || !f)
return f; int used = , flow, v; for (int i = cur[u]; ~i; i = nt[i])
if (dep[v = to[i]] == dep[u] + && fl[i])
{
flow = dfs(v, min(f - used, fl[i])); used += flow;
fl[i] -= flow;
fl[i^] += flow; if (used == f)
return f; if (fl[i])
cur[u] = i;
} if (!used)
dep[u] = ; return used;
} inline int maxFlow(void)
{
int maxFlow = , newFlow; while (bfs())
{
for (int i = s; i <= t; ++i)
cur[i] = hd[i]; while (newFlow = dfs(s, inf))
maxFlow += newFlow;
} return maxFlow;
} inline lnt sqr(lnt x)
{
return x * x;
} int gcd(int x, int y)
{
return y ? gcd(y, x % y) : x;
} inline bool check(int x, int y)
{
if (gcd(x, y) != )
return false; lnt t = sqr(x) + sqr(y);
if (sqr(sqrt(t)) != t)
return false; return true;
} signed main(void)
{
scanf("%d", &n); for (int i = ; i <= n; ++i)
scanf("%d", a + i); for (int i = ; i <= n; ++i)
b[i] = a[i]; s = , t = n + ; memset(hd, -, sizeof(hd)); for (int i = ; i <= n; ++i)
if (a[i] & )
add(s, i, b[i]);
else
add(i, t, b[i]); for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j)
if (a[i] & )if (!(a[j] & ))
if (check(a[i], a[j]))
add(i, j, inf); int sum = ; for (int i = ; i <= n; ++i)
sum += b[i]; printf("%d\n", sum - maxFlow());
}
@Author: YouSiki