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 }