【BZOJ】【3275】Numbers

网络流/最小割


  Orz了Jiry_2神犇,蒟蒻网络流建模什么的完全不会啊T_T

  按奇偶性来分组实在太巧妙了……然后相关的点之间连边表示只能选其一,来求最小割……

  1 /**************************************************************
  2     Problem: 3275
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:1252 ms
  7     Memory:1708 kb
  8 ****************************************************************/
  9  
 10 //BZOJ 3275
 11 #include<cmath>
 12 #include<vector>
 13 #include<cstdio>
 14 #include<cstring>
 15 #include<cstdlib>
 16 #include<iostream>
 17 #include<algorithm>
 18 #define rep(i,n) for(int i=0;i<n;++i)
 19 #define F(i,j,n) for(int i=j;i<=n;++i)
 20 #define D(i,j,n) for(int i=j;i>=n;--i)
 21 #define pb push_back
 22 using namespace std;
 23 inline int getint(){
 24     int v=0,sign=1; char ch=getchar();
 25     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
 26     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
 27     return v*sign;
 28 }
 29 const int N=3100,M=30010,INF=~0u>>2;
 30 typedef long long LL;
 31 /******************tamplate*********************/
 32 int n,m,a[3010],tot,ans;
 33 struct edge{
 34     int to,v;
 35 };
 36 int gcd(int a,int b){if (!b) return a;else return gcd(b,a%b);}
 37 bool judge(int a,int b){
 38     int s=a*a+b*b;
 39     int q=int(sqrt(s));
 40     if (q*q!=s) return 0;
 41     if (gcd(a,b)!=1) return 0;
 42     return 1;
 43 }
 44 struct Net{
 45     edge E[M];
 46     int head[N],next[M],cnt;
 47     bool vis[110][110];
 48     void ins(int x,int y,int v){
 49         E[++cnt]=(edge){y,v};
 50         next[cnt]=head[x]; head[x]=cnt;
 51     }
 52     void add(int x,int y,int v){
 53         ins(x,y,v); ins(y,x,0);
 54     }
 55     int s,t,cur[N],d[N],Q[N];
 56     void init(){
 57         n=getint();cnt=1;
 58         tot=ans=0;
 59         s=0; t=n+1;
 60         F(i,1,n){
 61             a[i]=getint();tot+=a[i];
 62             if (a[i]&1) add(s,i,a[i]);
 63             else add(i,t,a[i]);
 64         }
 65         F(i,1,n) if (a[i]&1)
 66             F(j,1,n) if ((a[j]&1)==0)
 67                 if (judge(a[i],a[j])) add(i,j,INF);
 68     }
 69     bool mklevel(){
 70         memset(d,-1,sizeof d);
 71         d[s]=0;
 72         int l=0,r=-1;
 73         Q[++r]=s;
 74         while(l<=r){
 75             int x=Q[l++];
 76             for(int i=head[x];i;i=next[i])
 77                 if (d[E[i].to]==-1 && E[i].v){
 78                     d[E[i].to]=d[x]+1;
 79                     Q[++r]=E[i].to;
 80                 }
 81         }
 82         return d[t]!=-1;
 83     }
 84     int dfs(int x,int a){
 85         if (x==t) return a;
 86         int flow=0;
 87         for(int &i=cur[x];i && flow<a;i=next[i])
 88             if (E[i].v && d[E[i].to]==d[x]+1){
 89                 int f=dfs(E[i].to,min(a-flow,E[i].v));
 90                 E[i].v-=f;
 91                 E[i^1].v+=f;
 92                 flow+=f;
 93             }
 94         if (!flow) d[x]=-1;
 95         return flow;
 96     }
 97     void Dinic(){
 98         while(mklevel()){
 99             F(i,s,t) cur[i]=head[i];
100             ans+=dfs(s,INF);
101         }
102     }
103 }G1;
104 int main(){
105 #ifndef ONLINE_JUDGE
106     freopen("3275.in","r",stdin);
107     freopen("3275.out","w",stdout);
108 #endif
109     G1.init(); G1.Dinic();
110     printf("%d\n",tot-ans);
111     return 0;
112 }
View Code

 

3275: Number

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 495  Solved: 217
[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

Sample Output

22

HINT

n<=3000。

Source

[Submit][Status][Discuss]
posted @ 2015-03-15 09:42  Tunix  阅读(368)  评论(0编辑  收藏  举报