BZOJ 3158 千钧一发 最小割

 

分析:

  偶数对满足条件2,所有奇数对满足条件1。

  如果你能一眼看出这个规律,这道题就完成了一半。

  我们只需要将数分为两类,a值为奇数,就从S向这个点连容量为b值的边,a值为偶数,就从这个点向T连容量为b值的边。

  暴力枚举,对于奇集合和偶集合中不能共存的两个数,连容量为无穷大的边。

  求出最小割,代表这个割集要被我们舍弃。

  然后直接用b值总和减去最小割就好。

代码:

 1 #include<bits/stdc++.h>
 2 #define ms(a,x) memset(a,x,sizeof(a))
 3 #define pf(x) (1LL*x*x)
 4 #define ll long long
 5 using namespace std;
 6 const int N=1005,M=500005,inf=0x3f3f3f3f;
 7 struct node{int y,z,nxt;}e[M*2];int S,T,tot=0;
 8 int d[N],h[N],c=1,a[N],b[N],q[N],n,m;ll s[N];
 9 int gcd(int x,int y){
10     return y?gcd(y,x%y):x;
11 } bool pd(ll x){
12     ll y=sqrt(x);return y*y!=x;
13 } void add(int x,int y,int z){
14     e[++c]=(node){y,z,h[x]};h[x]=c;
15     e[++c]=(node){x,0,h[y]};h[y]=c;
16 } bool bfs(){
17     int f=1,t=0;ms(d,-1);
18     q[++t]=S;d[S]=0;
19     while(f<=t){
20         int x=q[f++];
21         for(int i=h[x],y;i;i=e[i].nxt)
22         if(d[y=e[i].y]==-1&&e[i].z)
23         d[y]=d[x]+1,q[++t]=y;
24     } return (d[T]!=-1);
25 } int dfs(int x,int f){
26     if(x==T) return f;int w,tmp=0;
27     for(int i=h[x],y;i;i=e[i].nxt)
28     if(d[y=e[i].y]==d[x]+1&&e[i].z){
29         w=dfs(y,min(e[i].z,f-tmp));
30         if(!w) d[y]=-1;
31         e[i].z-=w;e[i^1].z+=w;tmp+=w;
32         if(tmp==f) return f;
33     } return tmp;
34 } void dinic(){
35     while(bfs()) tot+=dfs(S,inf);
36 } signed main(){
37     scanf("%d",&n);int ans=0;S=0;T=n+1;
38     for(int i=1;i<=n;i++)
39     scanf("%d",&a[i]),s[i]=pf(a[i]);
40     for(int i=1;i<=n;i++)
41     scanf("%d",&b[i]),ans+=b[i];
42     for(int i=1;i<=n;i++)
43     for(int j=i+1;j<=n;j++)
44     if(gcd(a[i],a[j])==1&&!pd(s[i]+s[j]))
45     a[i]&1?add(i,j,inf):add(j,i,inf);
46     for(int i=1;i<=n;i++)
47     a[i]&1?add(S,i,b[i]):add(i,T,b[i]);
48     dinic();printf("%d\n",ans-tot);
49     return 0;
50 }
最小割

 

posted @ 2019-01-10 17:05  杜宇一声  阅读(225)  评论(0编辑  收藏  举报