【BZOJ】【3275】Numbers
网络流/最小割
Orz了Jiry_2神犇,蒟蒻网络流建模什么的完全不会啊T_T
按奇偶性来分组实在太巧妙了……然后相关的点之间连边表示只能选其一,来求最小割……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
3275: Number
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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
3 4 5 6 7
Sample Output
22
HINT
n<=3000。