[bzoj3275]Number

暴力枚举两个数字并判定,如果不能同时选就连边,然后即求最大带权独立集。

普通图的最大带权独立集无法快速求出,但发现两个奇数一定无法使得1式成立(考虑模8,奇数平方模81,偶数平方模804),两个偶数一定无法使2式成立,因此奇数和偶数内部没有边,即形成了一张二分图。

首先假设所有数都可以选,考虑最少要删掉多少:1.将左半部分的点与源点连价值的边;2.将右半部分的点向汇点连价值的边;3.两者之间不能同时选的连一条inf的边。然后跑最小割,这样任意一条inf边的两端必须有一条边被删掉(不选),所以答案就是最大流了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 3005
 4 #define inf 0x3f3f3f3f
 5 struct ji{
 6     int nex,to,len;
 7 }edge[N*N];
 8 queue<int>q;
 9 int E,n,ans,a[N],head[N],work[N],d[N];
10 void add(int x,int y,int z){
11     edge[E].nex=head[x];
12     edge[E].to=y;
13     edge[E].len=z;
14     head[x]=E++;
15     if (E&1)add(y,x,0);
16 }
17 int gcd(int x,int y){
18     if (!y)return x;
19     return gcd(y,x%y);
20 }
21 bool bfs(){
22     memset(d,-1,sizeof(d));
23     q.push(0);
24     d[0]=0;
25     while (!q.empty()){
26         int k=q.front();
27         q.pop();
28         for(int i=head[k];i!=-1;i=edge[i].nex)
29             if ((edge[i].len)&&(d[edge[i].to]<0)){
30                 d[edge[i].to]=d[k]+1;
31                 q.push(edge[i].to);
32             }
33     }
34     return d[n+1]>=0;
35 }
36 int dfs(int k,int s){
37     if (k>n)return s;
38     int p;
39     for(int i=head[k];i!=-1;i=edge[i].nex)
40         if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){
41             p=dfs(edge[i].to,min(s,edge[i].len));
42             if (p){
43                 edge[i].len-=p;
44                 edge[i^1].len+=p;
45                 return p;
46             }
47         }
48     return 0;
49 }
50 int dinic(){
51     int k,ans=0;
52     while (bfs()){
53         memcpy(work,head,sizeof(head));
54         while (k=dfs(0,inf))ans+=k;
55     }
56     return ans;
57 }
58 int main(){
59     scanf("%d",&n);
60     memset(head,-1,sizeof(head));
61     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
62     for(int i=1;i<=n;i++)ans+=a[i];
63     for(int i=1;i<=n;i++)
64         if (a[i]&1)add(0,i,a[i]);
65         else add(i,n+1,a[i]);
66     for(int i=1;i<=n;i++)
67         if (a[i]&1)
68             for(int j=1;j<=n;j++){
69                 if (gcd(a[i],a[j])>1)continue;
70                 int c=a[i]*a[i]+a[j]*a[j];
71                 if (c==(int)sqrt(c)*(int)sqrt(c))add(i,j,inf);
72             }
73     printf("%d",ans-dinic());
74 }
View Code

 

posted @ 2019-07-28 10:37  PYWBKTDA  阅读(78)  评论(0编辑  收藏  举报