[bzoj4514] [Sdoi2016]数字配对

  费用流。。

  先把a数组里的数全部质因数分解,判断ai/aj是否为质数,就看质因数互相抵消后是不是只剩一个质因数。

  满足条件的数就连边

  接下来我想拆点建二分图。。然而由题解可得,连边的两个数 的质因数个数 的奇偶性肯定不同。。

  就相当于自带黑白染色...所以奇数个连汇,偶数个连源就行了= =

 

  因为有价值总和不小于0的限制。所以找到一条价值为负的增广路后,不一定能流满。

  但是因为求费用流的原始对偶算法自带限制流量的功能。。所以其实改一个数就能照常多路增广了= =

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #define ll long long
  5 using namespace std;
  6 const int maxn=205,inf1=1002333333;
  7 ll inf;
  8 struct zs{
  9     int too,pre,flow;
 10     ll cost;
 11 }e[1002333];int tot,last[maxn];
 12 int mp[maxn][23],mp1[maxn][23],psum[maxn],num[maxn];
 13 int a[maxn],b[maxn],c[maxn];
 14 int p[32333],pnum;
 15 int dl[100233];
 16 ll dis[maxn],sm;
 17 int i,j,k,n,m,ans,s,t;
 18 bool isp[32333],u[maxn],ins[maxn];
 19 
 20 
 21 int ra,fh;char rx;
 22 inline int read(){
 23     rx=getchar(),ra=0,fh=1;
 24     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
 25     if(rx=='-')fh=-1,rx=getchar();
 26     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
 27 }
 28 inline void insert(int a,int b,int c,ll d){
 29 //    printf("   %d-->%d  %d %lld\n",a,b,c,d);
 30     e[++tot].too=b,e[tot].flow=c,e[tot].cost=d ,e[tot].pre=last[a],last[a]=tot;
 31     e[++tot].too=a,e[tot].flow=0,e[tot].cost=-d,e[tot].pre=last[b],last[b]=tot;
 32 }
 33 inline void prerun_p(){
 34     int mx=32333;register int i,j;
 35     memset(isp,1,mx);
 36     isp[1]=0;
 37     for(i=2;i<mx;i++)if(isp[i])
 38         for(j=i<<1,p[++pnum]=i;j<mx;j+=i)isp[j]=0;
 39 }
 40 inline void prerun_div(){
 41     int tmp;register int j;
 42     for(int i=1;i<=n;i++){
 43         tmp=a[i];
 44         for(j=1;j<=pnum&&p[j]*p[j]<=tmp;j++)
 45             if(tmp%p[j]==0){
 46                 mp[i][++num[i]]=p[j];
 47                 while(tmp%p[j]==0)
 48                     ++mp1[i][num[i]],tmp/=p[j],psum[i]++;
 49             }
 50         if(tmp>1)mp[i][++num[i]]=tmp,mp1[i][num[i]]=1,psum[i]++;
 51     }
 52 }
 53 inline bool check(int i,int j){
 54     if(a[j]%a[i]!=0||psum[j]>psum[i]+1)return 0;
 55     if(a[i]==1)return psum[j]==1;
 56     register int k;int x=0;bool f;
 57     if(psum[j]>psum[i]){
 58         for(k=1,f=0;k<=num[j]&&x<2;k++)
 59             if(mp[j][k]!=mp[i][k-f])f=1,x+=mp1[j][k];else x+=mp1[j][k]-mp1[i][k-f];
 60         return x==1;
 61     }else{
 62         for(k=1;k<=num[j]&&x<2;k++)
 63             x+=mp1[j][k]-mp1[i][k];
 64         return x==1;
 65     }
 66 }
 67 inline void build(){
 68     int i,j,i1,j1;
 69     for(i=1;i<=n;i++)if(psum[i]&1)insert(i,t,b[i],0);else insert(s,i,b[i],0);
 70     for(i=1;i<=n;i++)for(j=1;j<=n;j++)
 71         if(a[i]<a[j]&&((psum[i]^psum[j])&1))
 72             if(check(i,j)){
 73                 if(psum[i]&1)i1=j,j1=i;else i1=i,j1=j;
 74                 insert(i1,j1,inf1,(ll)c[i]*c[j]);//printf("  checked:  %d %d\n",a[i],a[j]);
 75             }
 76 }
 77 
 78 
 79 inline bool spfa(){
 80     memset(dis,180,(t+1)<<3);
 81     int l=0,r=1,i,now;dl[1]=s,u[s]=1,dis[s]=0;
 82     while(l<r)
 83         for(now=dl[++l],u[now]=0,i=last[now];i;i=e[i].pre)
 84             if(e[i].flow&&dis[e[i].too]<dis[now]+e[i].cost){
 85                 dis[e[i].too]=dis[now]+e[i].cost;
 86                 if(!u[e[i].too])dl[++r]=e[i].too,u[e[i].too]=1;
 87             }
 88     return dis[t]>-inf;
 89 }
 90 inline int dfs(int x,int mx){
 91     if(x==t)return mx;
 92     int i,used=0,w;ins[x]=1;
 93     for(i=last[x];i;i=e[i].pre)if(e[i].flow&&dis[e[i].too]==dis[x]+e[i].cost&&!ins[e[i].too])
 94         if((w=dfs(e[i].too,min(mx-used,e[i].flow)))){
 95             used+=w,e[i].flow-=w,e[i^1].flow+=w;
 96             if(used==mx){ins[x]=0;return mx;}
 97         }
 98     ins[x]=0,dis[x]=-inf;return used;
 99 }
100 int main(){
101     inf=inf1;inf*=inf;
102     n=read();
103     for(i=1;i<=n;i++)a[i]=read();
104     for(i=1;i<=n;i++)b[i]=read();
105     for(i=1;i<=n;i++)c[i]=read();
106     prerun_p();prerun_div();
107     s=0,t=n+1,tot=1;
108     build();
109     int w;
110     while(spfa())
111         if(dis[t]>=0)w=dfs(s,inf1),sm+=dis[t]*w,ans+=w;
112         else{
113             if(sm+dis[t]<0)break;
114             w=dfs(s,sm/(-dis[t])),sm+=dis[t]*w,ans+=w;
115         }
116     printf("%d\n",ans);
117     return 0;
118 }
View Code

 然而这题主要耗时完全不在费用流上QAQ

posted @ 2016-04-28 23:47  czllgzmzl  阅读(276)  评论(0编辑  收藏  举报