您的位置:首页 > 其它

[bzoj3275]Number

2017-02-25 15:57 204 查看

题目大意

两个a和b不能同时选需要同时满足两个条件

1、a^2+b^2是一个完全平方数

2、(a,b)=1

选一些数使和最大

最小割

这个不能同时选条件好像没什么规律。

但是,两个奇数一定能同时选。

为什么?

奇数的平方是奇数,偶数的平方是偶数

两个奇数的平方和是个偶数,如果还是完全平方数,那么就是一个偶数的平方。

奇数用(2k+1)表示,(2k+1)^2=4k^2+1+4k

在模4意义下余1,那两个奇数的平方和在模4意义下余2

而偶数的平方在模4意义下显然为0

然后,两个偶数一定能同时选

偶数和偶数的gcd为2嘛。。

这样,两个数不能同时选,一定一个是奇数,另一个是偶数!

这是个二分图,如果i和j不能同时选就连一条边。

怎么求最大的和呢?

可以考虑求不不选的数的最小的和。

这就是最小割,同时选的点间连正无穷的边就可以表示这两个不能同时不割!

#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=3000+10,maxm=5000000+10,inf=1000000000;
int a[maxn],h[maxn],now[maxn],d[maxn],go[maxm],dis[maxm],fx[maxm],next[maxm];
bool bz[maxn];
int i,j,k,l,r,s,t,n,m,tot,ans;
void add(int x,int y,int z,int d){
go[++tot]=y;
dis[tot]=z;
fx[tot]=tot+d;
next[tot]=h[x];
h[x]=tot;
}
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
bool pd(int i,int j){
if (gcd(a[i],a[j])!=1) return 0;
int t=a[i]*a[i]+a[j]*a[j];
if (floor(sqrt(t))*floor(sqrt(t))==t) return 1;else return 0;
}
int dfs(int x,int flow){
if (x==t){
ans+=flow;
return flow;
}
bz[x]=1;
int r=now[x],k;
while (r){
if (!bz[go[r]]&&dis[r]&&d[x]==d[go[r]]+1){
k=dfs(go[r],min(flow,dis[r]));
if (k){
dis[r]-=k;
dis[fx[r]]+=k;
now[x]=r;
return k;
}
}
r=next[r];
}
return now[x]=0;
}
bool change(){
int i,r,tmp=inf;
fo(i,s,t)
if (bz[i]){
r=h[i];
while (r){
if (!bz[go[r]]&&dis[r]&&d[go[r]]+1-d[i]<tmp) tmp=d[go[r]]+1-d[i];
r=next[r];
}
}
if (tmp==inf) return 0;
fo(i,s,t)
if (bz[i]) d[i]+=tmp;
return 1;
}
int main(){
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,n)
if (a[i]%2==1)
fo(j,1,n)
if (a[j]%2==0&&pd(i,j)){
add(i+1,j+1,inf,1);
add(j+1,i+1,0,-1);
}
s=1;t=n+2;
fo(i,1,n)
if (a[i]%2==1){
add(s,i+1,a[i],1);
add(i+1,s,0,-1);
}
else{
add(i+1,t,a[i],1);
add(t,i+1,0,-1);
}
do{
fo(i,s,t) now[i]=h[i];
fill(bz+s,bz+t+1,0);
while (dfs(s,inf)) fill(bz+s,bz+t+1,0);
}while (change());
ans=-ans;
fo(i,1,n) ans+=a[i];
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: