题目描述
有N个正整数,需要从中选出一些数,使这些数的和最大。
若两个数a,b同时满足以下条件,则a,b不能同时被选
1:存在正整数C,使a*a+b*b=c*c
2:gcd(a,b)=1
Sol
太菜不会分析+网络流经典模型学习&总结不到位
一开始果断看出这是个最大独立集啊
然后好像不会跑?
分析一下连边情况,首先偶数不会和偶数相连,因为不满足第2个条件
对于第一个式子:
令
a=2k+1,b=2k′+1
a
=
2
k
+
1
,
b
=
2
k
′
+
1
于是
c=4(k2+k′2)+4(k+k′)+2
c
=
4
(
k
2
+
k
′
2
)
+
4
(
k
+
k
′
)
+
2
,
cmod4=2
c
m
o
d
4
=
2
简单分析发现c不会是完全平方数
所以只有可能奇数和偶数连边,打个表发现 105 10 5 有1万7千多这样的数对
所以就是一个普通的二分图最大独立集了一波Dinic最小割即可
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<cstring>
#define Copy(a,b) memcpy(a,b,sizeof(a))
#define Set(a,b) memset(a,b,sizeof(a))
using namespace std;
int n;
const int N=3e3+10;
const int INF=3e8+10;
int a[N];
int gcd(int a,int b){return b==0? a:gcd(b,a%b);}
const int MAXN=1e5+10;
typedef long long ll;
inline bool check(int a,int b){
if(!(a&1)&&!(b&1)) return 0;
if(gcd(a,b)!=1) return 0;
ll c=1ll*a*a+1ll*b*b;
register ll res=sqrt(c);if(res*res==c) return 1;
return 0;
}
int ans=0;
int num[MAXN];
struct edge{
int to;int next;int cap;
}A[MAXN];
int head[N];int cnt=0;int cur[N];
void add(int x,int y,int cap){A[cnt]=(edge){y,head[x],cap};head[x]=cnt++;}
int S,T;
int Sum=0;
int d[N];
queue<int> Q;
inline bool bfs(){
while(!Q.empty()) Q.pop();
Set(d,-1);d[S]=0;Q.push(S);
while(!Q.empty()){
register int u=Q.front();Q.pop();
for(register int v,i=head[u];~i;i=A[i].next){
v=A[i].to;
if(A[i].cap<=0||d[v]!=-1) continue;
d[v]=d[u]+1;Q.push(v);
if(v==T) return 1;
}
}
return (d[T]!=-1);
}
int dfs(int u,int flow){
if(flow==0) return 0;
if(u==T) return flow;
int delta=flow;
for(register int v,&i=cur[u];~i;i=A[i].next){
v=A[i].to;
if(A[i].cap<=0||d[v]!=d[u]+1) continue;
register int fl=dfs(v,min(flow,A[i].cap));
if(fl==0) d[v]=-1;
flow-=fl;A[i].cap-=fl;A[i^1].cap+=fl;
if(flow==0) break;
}
return (delta-flow);
}
inline void Dinic()
{
register int flow=0;
while(bfs()) {Copy(cur,head);flow+=dfs(S,INF);}
printf("%d\n",Sum-flow);
}
int main()
{
scanf("%d",&n);Set(head,-1);
for(register int i=1;i<=n;++i) scanf("%d",&a[i]),++num[a[i]],Sum+=a[i];
sort(a+1,a+1+n);n=unique(a+1,a+1+n)-a-1;S=0;
for(register int i=1;i<=n;++i)
for(register int j=i+1;j<=n;++j){
if(check(a[i],a[j])) {
if(a[i]&1) add(i,j,INF),add(j,i,0);
else add(j,i,INF),add(i,j,0);
}
}
T=n+1;
for(register int i=1;i<=n;++i){
if(a[i]&1) add(S,i,a[i]*num[a[i]]),add(i,S,0);
else add(i,T,a[i]*num[a[i]]),add(T,i,0);
}
Dinic();
return 0;
}