title
BZOJ 3275
Description
There are N positive integers, from which we need to select some numbers to make the sum of these numbers the largest.
If two numbers a and B satisfy the following conditions at the same time, then a and B cannot be selected at the same time
1: There is a positive integer C, so that a * a+b * b=c * c
2:gcd(a,b)=1
Input
The first line is a positive integer n, representing the number of numbers. N<=3000
The second line contains n positive integers a1,a2,... an
Output
Maximum sum
Sample Input
5
3 4 5 6 7
Sample Output
22
analysis
Now I feel like a very routine topic. Let's talk about drawing directly.
- The dismantling point, because it can only be taken once, the source point is connected to the entry point, the exit point is connected to the confluence point, and the capacity is a[i]a[i]a[i];
- The two points satisfying the condition of the topic are connected, and the capacity is INFINFINF.
- Running maximum flow and minimum cut;
- The final answer is a[i] maxflow/2 sum a[i] - maxflow/2 a[i] maxflow/2 (code code code is sum ans / 2sum ans/2 sum ans/2).
code
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10,maxm=1e6+10,inf=0x3f3f3f3f; char buf[1<<15],*fs,*ft; inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; } template<typename T>inline void read(T &x) { x=0; T f=1, ch=getchar(); while (!isdigit(ch) && ch^'-') ch=getchar(); if (ch=='-') f=-1, ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar(); x*=f; } template<typename T>inline void write(T x) { if (!x) { putchar('0'); return ; } if (x<0) putchar('-'), x=-x; T num=0, ch[20]; while (x) ch[++num]=x%10+48, x/=10; while (num) putchar(ch[num--]); } int ver[maxm],edge[maxm],Next[maxm],head[maxn],len=1; inline void add(int x,int y,int z) { ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len; ver[++len]=x,edge[len]=0,Next[len]=head[y],head[y]=len; } int s,t; int dist[maxn]; inline bool bfs() { queue<int>q; memset(dist,0,sizeof(dist)); q.push(s);dist[s]=1; while (!q.empty()) { int x=q.front(); q.pop(); for (int i=head[x]; i; i=Next[i]) { int y=ver[i]; if (edge[i] && !dist[y]) { dist[y]=dist[x]+1; if (y==t) return 1; q.push(y); } } } return 0; } inline int get(int x,int low) { if (x==t) return low; int tmp=low; for (int i=head[x]; i; i=Next[i]) { int y=ver[i]; if (edge[i] && dist[y]==dist[x]+1) { int a=get(y,min(tmp,edge[i])); if (!a) dist[y]=0; edge[i]-=a; edge[i^1]+=a; if (!(tmp-=a)) break; } } return low-tmp; } inline int gcd(int a,int b) { return b?gcd(b,a%b):a; } inline bool check(int a,int b)//Conditions for this question { int s=a*a+b*b,q=(int)sqrt(s); if (q*q!=s || gcd(a,b)!=1) return 0; return 1; } int a[maxn]; int main() { int n;read(n); int sum=0,ans=0; s=0,t=n<<1|1; for (int i=1; i<=n; ++i) read(a[i]),add(s,i,a[i]),add(i+n,t,a[i]),sum+=a[i];//Disassemble points, each can only be taken once for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) if (check(a[i],a[j])) add(i,j+n,inf),add(j,i+n,inf);//If you satisfy the conditions, take one and the other. while (bfs()) ans+=get(s,inf); write(sum-ans/2);//So the number of final choices is double, so divide by two. return 0; }