【bzoj3158】千钧一发 最小割

Input

第一行一个正整数N。

第二行共包括N个正整数,第 个正整数表示Ai。

第三行共包括N个正整数,第 个正整数表示Bi。

Output

共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。

Sample Input

4
3 4 5 12
9 8 30 9

Sample Output

39

HINT

1<=N<=1000,1<=Ai,Bi<=10^6

题解

可以证明,任意两个偶数满足2

两个奇数满足1

(2a+1)^2+(2b+1)^2=2(2a^2+2b^2+2a+2b+1)

一定不是完全平方数

所以可以用最小割解决此题

 

连向S表示选择偶数,连向T表示选择奇数,

因为两个奇数,两个偶数都有一些奇怪的性质,如上,

然后如果两个都不满足,那么就连一条边,表示只能选其中一个。

  1 #include<cstring>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cstdio>
  6 #include<queue>
  7 
  8 #define ll long long
  9 #define inf 2000000007
 10 #define N 1007
 11 #define M 1500007
 12 using namespace std;
 13 inline int read()
 14 {
 15     int x=0,f=1;char ch=getchar();
 16     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 17     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
 18     return x*f;
 19 }
 20 
 21 int ans,n,S,T;
 22 int a[N],b[N];
 23 int cnt,hed[N],nxt[M],rea[M],val[M],cur[N];
 24 int dis[N];
 25 
 26 void add(int u,int v,int w)
 27 {
 28     nxt[++cnt]=hed[u];
 29     hed[u]=cnt;
 30     rea[cnt]=v;
 31     val[cnt]=w;
 32 }
 33 void add_two_way(int u,int v,int w){add(u,v,w),add(v,u,0);}
 34 ll sqr(ll x){return x*x;}
 35 int gcd(int a,int b){return b?gcd(b,a%b):a;}
 36 bool check(int x,int y)
 37 {
 38 //    cout<<x<<" "<<y<<endl;
 39     ll sum=sqr(a[x])+sqr(a[y]),sum1=(ll)sqrt(sum);
 40     if (sqr(sum1)!=sum) return true;
 41     if (gcd(a[x],a[y])>1) return true;
 42 //    cout<<x<<" "<<y<<endl;
 43     return false;
 44 }
 45 bool bfs()
 46 {
 47     for (int i=S;i<=T;i++)dis[i]=-1;
 48     dis[S]=0;queue<int>q;q.push(S);
 49     while(!q.empty())
 50     {
 51         int u=q.front();q.pop();
 52         for (int i=hed[u];i!=-1;i=nxt[i])
 53         {
 54             int v=rea[i],w=val[i];
 55             if (w==0||dis[v]!=-1)continue;
 56             dis[v]=dis[u]+1;
 57             if (v==T)return 1;
 58             q.push(v);
 59         }
 60     }
 61     return 0;
 62 }
 63 int dfs(int u,int MX)
 64 {
 65     if (u==T||MX==0)return MX;
 66     int res=0;
 67     for (int i=cur[u];i!=-1;i=nxt[i])
 68     {
 69         int v=rea[i],w=val[i];
 70         if (dis[v]!=dis[u]+1)continue;
 71         int x=dfs(v,min(MX,w));
 72         cur[u]=i,res+=x,MX-=x;
 73         val[i]-=x,val[i^1]+=x;
 74         if (!MX)break;
 75     }
 76     if (!res)dis[u]=-1;
 77     return res;
 78 }
 79 void dinic()
 80 {
 81 //    cout<<"ans="<<ans<<endl;
 82     while(bfs())
 83     {
 84 //        cout<<2<<endl;
 85         for (int i=S;i<=T;i++)cur[i]=hed[i];
 86         ans-=dfs(S,inf);
 87 //        cout<<3<<endl;
 88     }
 89 }
 90 int main()
 91 {
 92     freopen("fzy.in","r",stdin);
 93     freopen("fzy.out","w",stdout);
 94     
 95     cnt=1;memset(hed,-1,sizeof(hed));
 96     n=read();
 97     for (int i=1;i<=n;i++)a[i]=read();
 98     for (int i=1;i<=n;i++)b[i]=read(),ans+=b[i];
 99     S=0,T=n+1;
100     for (int i=1;i<=n;i++)
101         if (a[i]%2==0) add_two_way(S,i,b[i]);
102         else add_two_way(i,T,b[i]);
103     for (int i=1;i<=n;i++)
104         for (int j=1;j<=n;j++)
105             if ((a[i]%2==0)&&(a[j]%2==1))
106                 if (!check(i,j)) add_two_way(i,j,inf);
107     dinic();
108     printf("%d",ans);
109 }

 

posted @ 2018-01-15 10:19  Kaiser-  阅读(142)  评论(0编辑  收藏  举报