【BZOJ3275】Number 最小割

【BZOJ3275】Number

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

Sample Output

22

HINT

n<=3000。

题解:先是无脑码了个最小割,果断WA了,看网上才又get了一个新定理

易证:奇数和奇数的平方和一定不是完全平方数,偶数和偶数的gcd一定不为1

然后就把所有的数分成奇数和偶数两个集合,然后再跑最小割就完事了

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
int n,cnt,tot,ans,tx,ty;
queue<int> q;
int vx[3010],vy[3010],next[1000000],head[6010],to[1000000],val[1000000],d[6010];
int gcd(int a,int b)
{
    return (b==0)?a:gcd(b,a%b);
}
int dfs(int x,int mf)
{
    if(x==n+1)  return mf;
    int i,k,temp=mf;
    for(i=head[x];i!=-1;i=next[i])
    {
        if(d[to[i]]==d[x]+1&&val[i])
        {
            k=dfs(to[i],min(temp,val[i]));
            if(!k)  d[to[i]]=0;
            val[i]-=k,val[i^1]+=k,temp-=k;
            if(!temp)   break;
        }
    }
    return mf-temp;
}
int bfs()
{
    int i,u;
    memset(d,0,sizeof(d));
    while(!q.empty())   q.pop();
    q.push(0),d[0]=1;
    while(!q.empty())
    {
        u=q.front(),q.pop();
        for(i=head[u];i!=-1;i=next[i])
        {
            if(!d[to[i]]&&val[i])
            {
                d[to[i]]=d[u]+1;
                if(to[i]==n+1)  return 1;
                q.push(to[i]);
            }
        }
    }
    return 0;
}
void add(int a,int b,int c)
{
    to[cnt]=b;
    val[cnt]=c;
    next[cnt]=head[a];
    head[a]=cnt++;
}
int main()
{
    scanf("%d",&n);
    int i,j,k;
    memset(head,-1,sizeof(head));
    for(i=1;i<=n;i++)
    {
        scanf("%d",&k);
        tot+=k;
        if(k&1) vx[++tx]=k;
        else    vy[++ty]=k;
    }
    for(i=1;i<=tx;i++)   add(0,i,vx[i]),add(i,0,0);
    for(i=1;i<=ty;i++)   add(i+tx,n+1,vy[i]),add(n+1,i+tx,0);
    for(i=1;i<=tx;i++)
    {
        for(j=1;j<=ty;j++)
        {
            if(gcd(vx[i],vy[j])!=1) continue;
            int k=vx[i]*vx[i]+vy[j]*vy[j];
            if(int(sqrt(k*1.0)+0.00001)*int(sqrt(k*1.0)+0.00001)==k)
            {
                add(i,tx+j,1<<30);
                add(tx+j,i,0);
            }
        }
    }
    while(bfs())    ans+=dfs(0,1<<30);
    printf("%d",tot-ans);
    return 0;
}

 

posted @   CQzhangyu  阅读(456)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示