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
3 4 5 6 7
Sample Output
22
HINT
n<=3000。
Source
题解:
先将求最大值改为负的最小费用
选了一个数x看成造成-x的费用,同时选了不能同时选的点对看成inf的费用
然后发现K值是负的,那么这个图有没有二分图性质呢
答案显然是有的(不然有这题干什么)
若存在正整数a,b,c,满足a2+b2=c2,且a,b互质,那么a和b的奇偶性不同
证明:正整数显然表示成4k,4k+1,4k+2,4k+3中的一种
而 (4k)2 mod 4 = 0
(4k+1)2 mod 4 = 1
(4k+2)2 mod 4 = 0
(4k+3)2 mod 4 = 1
显然 (a2 mod 4)+(b2 mod 4)=(c2 mod 4)
1. c如果为 4k 或 4k+2,只有a2 mod 4和b2 mod 4都是0才有可能满足上式,但这不满足a,b互质的要求(显然a和b此时都是偶数)
2. c如果为 4k+1 或 4k+3,a2 mod 4和b2 mod 4不能同为0或1,此时a,b的奇偶性不同
所以只有可能在一对奇偶不同的数才由可能建边,所以这个图有二分图性质
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 3005 7 #define maxm 6000000 8 #define inf 1061109567 9 using namespace std; 10 char ch; 11 bool ok; 12 void read(int &x){ 13 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 14 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 15 if (ok) x=-x; 16 } 17 int n,a[maxn],sum; 18 struct flow{ 19 int s,t,tot,now[maxn],son[maxm],pre[maxm],val[maxm]; 20 int dis[maxn],head,tail,list[maxn]; 21 bool bo[maxn]; 22 void init(){s=0,t=n+1,tot=1,memset(now,0,sizeof(now));} 23 void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} 24 void add(int a,int b,int c){put(a,b,c),put(b,a,0);} 25 bool bfs(){ 26 memset(bo,0,sizeof(bo)); 27 head=0,tail=1,list[1]=s,dis[s]=0,bo[s]=1; 28 while (head<tail){ 29 int u=list[++head]; 30 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 31 if (val[p]&&!bo[v]) bo[v]=1,dis[v]=dis[u]+1,list[++tail]=v; 32 } 33 return bo[t]; 34 } 35 int dfs(int u,int rest){ 36 if (u==t) return rest; 37 int ans=0; 38 for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p]) 39 if (val[p]&&dis[v]==dis[u]+1){ 40 int d=dfs(v,min(rest,val[p])); 41 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d; 42 } 43 if (!ans) dis[u]=-1; 44 return ans; 45 } 46 int dinic(){ 47 int ans=0; 48 while (bfs()) ans+=dfs(s,inf); 49 return ans; 50 } 51 }f; 52 int gcd(int a,int b){return b?gcd(b,a%b):a;} 53 int main(){ 54 read(n),f.init(); 55 for (int i=1;i<=n;i++){ 56 read(a[i]),sum+=a[i]; 57 if (a[i]&1) f.add(i,f.t,a[i]); else f.add(f.s,i,a[i]); 58 } 59 for (int i=1;i<=n;i++) if (!(a[i]&1)) for (int j=1;j<=n;j++) if (a[j]&1){ 60 int tmp=round(sqrt(a[i]*a[i]+a[j]*a[j])); 61 if (gcd(a[i],a[j])==1&&tmp*tmp==a[i]*a[i]+a[j]*a[j]) f.add(i,j,inf); 62 } 63 printf("%d\n",sum-f.dinic()); 64 return 0; 65 }