BZOJ 3158: 千钧一发

来源:互联网 发布:一个c语言程序的编写 编辑:程序博客网 时间:2024/05/17 09:05

居然还要数学知识

第一个条件可以知道a和b一定是一奇一偶

第二个条件是不互质

套用最大权闭合图建图方法,s向所有a[i]为奇数的连一条容量b[i]的边,所有a[i]为偶数的向t连一条容量b[i]的边

然后枚举判断:若奇数的a[i]和偶数的a[j]不满足条件,连一条从i到j的容量为正无穷的边

跑一边最大流,答案是sigma b[i]-最小割(最大流)


#include<cstdio>#include<algorithm>#include<vector>#include<queue>#include<cstring>#include<cmath>#define N 1005#define M 1000005#define INF 2e9#define LL long longusing namespace std; int read(){    int a=0,f=1;char c=getchar();    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}    while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}    return a*f;} struct edge{int to,f;}e[M];vector<int>G[N];int n,m,sum,S,T;int a[N],b[N],d[N],cur[N]; void add(int x,int y,int v){    e[m].to=y,e[m].f=v;    G[x].push_back(m++);    e[m].to=x,e[m].f=0;    G[y].push_back(m++);} bool bfs(){    queue<int>Q;    memset(d,-1,sizeof(d));    d[S]=0,Q.push(S);    while(!Q.empty())    {        int x=Q.front();Q.pop();        if(x==T) return 1;        for(int i=0;i<G[x].size();++i)        {            edge tmp=e[G[x][i]];            if(d[tmp.to]==-1&&tmp.f)            {                Q.push(tmp.to);                d[tmp.to]=d[x]+1;            }        }    }    return 0;} int dfs(int x,int a){    if(x==T) return a;    int flow=0,f;    for(int &i=cur[x];i<G[x].size();++i)    {        int y=G[x][i];        if(e[y].f&&d[e[y].to]==d[x]+1)        {            f=dfs(e[y].to,min(a,e[y].f));            e[y].f-=f;            e[y^1].f+=f;            flow+=f;            a-=f;            if(a==0) break;        }    }    if(!flow) d[x]=-1;    return flow;} void dinic(){    while(bfs())    {        memset(cur,0,sizeof(cur));        sum-=dfs(S,INF);    }} int gcd(int a,int b){return b==0?a:gcd(b,a%b);} bool check(LL x,LL y){    LL t=x*x+y*y,p=sqrt(t);    if(p*p!=t) return 1;    if(gcd(x,y)>1) return 1;    return 0;} int main(){    n=read();m=0;    for(int i=1;i<=n;++i) a[i]=read();    sum=0,S=0,T=n+1;    for(int i=1;i<=n;++i) sum+=(b[i]=read());    for(int i=1;i<=n;++i)        if(a[i]%2==1) add(S,i,b[i]);        else add(i,T,b[i]);    for(int i=1;i<=n;++i)        for(int j=1;j<=n;++j)            if(i!=j&&a[i]%2==1&&a[j]%2==0&&!check(a[i],a[j]))                add(i,j,INF);    dinic();    printf("%d",sum);    return 0;}