[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 }
然而这题主要耗时完全不在费用流上QAQ