2019 HL SC day2
今天讲的是网络流 大部分题目都写过了 这里 就总结一番。
bzoj 1066 裸的最大流 不过需要拆点细节方面有一点坑 剩下的 没什么了。
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define ll long long
#define INF 1000000000
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin)),fs==ft)?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int MAXN=,maxn=;
int n,m,h,t,S,T,c,maxflow,cnt,num,len=;
int q[MAXN],vis[MAXN];
char a[maxn][maxn],b[maxn][maxn];
int pos[maxn][maxn],dis[maxn][maxn];
int lin[MAXN],nex[MAXN],ver[MAXN],e[MAXN];
int dx[]={,,,,-};
int dy[]={,,-,,};
inline void add(int x,int y,int z)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=;
}
inline void bfs(int x,int y)
{
memset(dis,,sizeof(dis));
h=t=;q[++t]=x;vis[t]=y;
//cout<<x<<' '<<y<<endl;
while(h++<t)
{
for(int i=;i<=;++i)
{
int xx=q[h]+dx[i];
int yy=vis[h]+dy[i];
if(xx<||yy<||xx>n||yy>m)continue;
if(xx==x&&yy==y)continue;
if(dis[xx][yy])continue;
dis[xx][yy]=dis[q[h]][vis[h]]+;
if(dis[xx][yy]>c)continue;
if(a[xx][yy]!='')add(pos[x][y]+num,pos[xx][yy],INF);
q[++t]=xx;vis[t]=yy;
}
}
if(min(x,y)<=c||min((n-x+),(m-y+))<=c)
{
//cout<<x<<' '<<y<<endl;
add(pos[x][y]+num,T,INF);
}
}
inline int bfs()
{
memset(vis,,sizeof(vis));
h=t=;q[++t]=S;vis[S]=;
while(h++<t)
{
int x=q[h];
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!e[i]||vis[tn])continue;
vis[tn]=vis[x]+;
q[++t]=tn;
if(tn==T)return ;
}
}
return ;
}
inline int dinic(int x,int flow)
{
if(x==T)return flow;
int rest=flow,k;
for(int i=lin[x];i&&rest;i=nex[i])
{
int tn=ver[i];
if(e[i]&&vis[tn]==vis[x]+)
{
k=dinic(tn,min(e[i],rest));
if(!k)vis[tn]=;
e[i]-=k;e[i^]+=k;
rest-=k;
}
}
return flow-rest;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();c=read();
for(int i=;i<=n;++i)scanf("%s",a[i]+);
for(int i=;i<=n;++i)scanf("%s",b[i]+);
S=n*m*+;T=S+;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
pos[i][j]=++num;
if(b[i][j]!='L')continue;
++cnt;add(S,cnt+n*m*,);
add(cnt+n*m*,pos[i][j],);
}
for(int i=;i<=n;++i)
{
for(int j=;j<=m;++j)
if(a[i][j]!='')
{
add(pos[i][j],pos[i][j]+num,a[i][j]-'');
bfs(i,j);
}
}
int flow=;while(bfs())while((flow=dinic(S,INF)))maxflow+=flow;
printf("%d\n",cnt-maxflow);
return ;
}
bzoj 3993 最大流 需要二分一下答案 然后最大流分配攻击 看能否全部攻击。有点小卡精度 需要*10000 实数上二分较好。
//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define RE register
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
RE int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=,maxn=;
int n,m,len=,S,T,h,t;
int c[MAXN][MAXN],flag[MAXN];
int lin[maxn],nex[maxn],ver[maxn],vis[maxn],q[maxn];
ll e[maxn],a[MAXN],b[MAXN],ti,sum;
inline void add(int x,int y,ll z)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=;
}
inline int bfs()
{
memset(vis,,sizeof(vis));
h=t=;q[++t]=S;vis[S]=;
while(h++<t)
{
int x=q[h];
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!e[i]||vis[tn])continue;
vis[tn]=vis[x]+;
q[++t]=tn;
if(tn==T)return ;
}
}
return ;
}
inline ll dinic(int x,ll flow)
{
if(x==T)return flow;
ll rest=flow,k;
for(int i=lin[x];i&&rest;i=nex[i])
{
int tn=ver[i];
if(e[i]&&vis[tn]==vis[x]+)
{
k=dinic(tn,min(e[i],rest));
if(!k)vis[tn]=;
e[i]-=k;e[i^]+=k;
rest-=k;
}
}
return flow-rest;
}
inline int check()
{
ll flow=,maxflow=;
while(bfs())while((flow=dinic(S,INF*10000ll)))maxflow+=flow;
return maxflow==sum;
}
inline void build(ll x)
{
len=;memset(lin,,sizeof(lin));
for(int i=;i<=m;++i)add(S,i,x*b[i]);
for(int i=;i<=n;++i)add(i+m,T,a[i]);
for(int i=;i<=m;++i)
for(int j=;j<=n;++j)
if(c[i][j])add(i,j+m,INF*10000ll);
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
S=n+m+;T=S+;
for(int i=;i<=n;++i)a[i]=read()*10000ll,sum+=a[i];
for(int i=;i<=m;++i)b[i]=read();
for(int i=;i<=m;++i)
for(int j=;j<=n;++j)
{
c[i][j]=read();
if(c[i][j]&&!flag[j])ti+=a[j],flag[j]=;
}
ll l=,r=ti;
while(l+<r)
{
ll mid=(l+r)>>;
build(mid);
if(check())r=mid;
else l=mid;
}
build(l);
if(check())printf("%.4lf",(double)l/10000.0);
else printf("%.4lf",(double)r/10000.0);
return ;
}
luogu 4126 很难的最小割问题。竟然还需要tarjan 。。我有点蠢迷了将近20min 才发现一些性质被我完美的忽略掉了。
1 跑一边最大流 不满流的边一定不会属于割集 显然 我们将其割掉 那么再割掉其他边 那么最小割将>最大流故 不满流的边一定不会属于割集
2 满流的边有可能属于 割集 有可能也不属于割集 因为存在 流光往一处流的可能。。
//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define RE register
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
RE int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=,maxn=<<;
int n,m,len=,S,T,maxflow,t,h,num,cnt,top;
int q[MAXN],vis[MAXN],dfn[MAXN],low[MAXN],c[MAXN],s[MAXN];
int lin[MAXN],nex[maxn],ver[maxn],e[maxn];
inline void add(int x,int y,int z)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=;
}
struct wy
{
int x,y,id;
}w[maxn];
inline int bfs()
{
memset(vis,,sizeof(vis));
h=t=;q[++t]=S;vis[S]=;
while(h++<t)
{
int x=q[h];
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!e[i]||vis[tn])continue;
q[++t]=tn;vis[tn]=vis[x]+;
if(tn==T)return ;
}
}
return ;
}
inline int dinic(int x,int flow)
{
if(x==T)return flow;
int rest=flow,k;
for(int i=lin[x];i&&rest;i=nex[i])
{
int tn=ver[i];
if(vis[tn]==vis[x]+&&e[i])
{
k=dinic(tn,min(e[i],rest));
if(!k){vis[tn]=;continue;}
e[i]-=k;e[i^]+=k;rest-=k;
}
}
return flow-rest;
}
inline void tarjan(int x)
{
dfn[x]=low[x]=++num;
s[++top]=x;vis[x]=;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(e[i]==)continue;
if(!dfn[tn])
{
tarjan(tn);
low[x]=min(low[x],low[tn]);
}
else if(vis[tn])low[x]=min(low[x],dfn[tn]);
}
if(dfn[x]==low[x])
{
++cnt;int y;
do
{
y=s[top--];
vis[y]=;
c[y]=cnt;
}while(x!=y);
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();S=read();T=read();
for(int i=;i<=m;++i)
{
int x,y,z;
x=read();y=read();z=read();
add(x,y,z);
w[i]=(wy){x,y,len-};
}
int flow=;
while(bfs())while((flow=dinic(S,INF)))maxflow+=flow;
//printf("%d\n",maxflow);
//problem 1:是否存在一个最小割的切断方案该道路属于割集
//problem 2:当前路径是否在任意一个割集中都存在
//对于问题2 显然的是如果一定是割集的话意味着流入量比当前容量大 可流出量也比当前容量大+1则增大流量
//那么这条边的左端点一定是和S属于同一个强连通分量之中 右端点和T在同一个强联通分量当中
//对于问题1 显然暴力可以判断 当然两端如果还能互相到达 那么一定不会属于割集
//证明:设这条边左断点为u 右端点为v 且当前满流 v通过反向边一定可以到u u能到v当且仅当从u出发能到T
//故切掉这条边还有流能到T 若此边属于此割集 就一定不存在这样的流 所以假设不成立。
//得证。
for(int i=;i<=n;++i)if(!dfn[i])tarjan(i);
for(int i=;i<=m;++i)
{
if(e[w[i].id])printf("%d %d\n",,);
else
{
if(c[w[i].x]!=c[w[i].y])
{
printf("%d ",);
//cout<<c[w[i].x]<<' '<<c[S]<<endl;
//cout<<c[w[i].y]<<' '<<c[T]<<endl;
if(c[w[i].x]==c[S]&&c[w[i].y]==c[T])printf("%d\n",);
else printf("%d\n",);
}
else printf("%d %d\n",,);
}
}
return ;
}
具体怎么写见代码注释。
bzoj 3894 文理分科 最小割裸题 虚建几个点即可。
//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db double
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=,maxn=;
int n,m,len=,maxflow,S,T,t,h,sum,cnt;
int pos[MAXN][MAXN];
int vis[maxn],q[maxn];
int lin[maxn],ver[maxn],nex[maxn],e[maxn];
const int dx[]={,,,,-};
const int dy[]={,,-,,};
inline void add(int x,int y,int z)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=;
}
inline int bfs()
{
memset(vis,,sizeof(vis));
h=t=;q[++t]=S;vis[S]=;
while(h++<t)
{
int x=q[h];
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!e[i]||vis[tn])continue;
vis[tn]=vis[x]+;
q[++t]=tn;
if(tn==T)return ;
}
}
return ;
}
inline int dinic(int x,int flow)
{
if(x==T)return flow;
int rest=flow,k;
for(int i=lin[x];i&&rest;i=nex[i])
{
int tn=ver[i];
if(e[i]&&vis[tn]==vis[x]+)
{
k=dinic(tn,min(e[i],rest));
if(!k)vis[tn]=;
e[i]-=k;e[i^]+=k;
rest-=k;
}
}
return flow-rest;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
S=n*m+;T=S+;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
int x;
x=read();sum+=x;
pos[i][j]=++cnt;
add(S,pos[i][j],x);
}
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
int x=read();sum+=x;
add(pos[i][j],T,x);
}
cnt=T;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
int x=read();
add(S,++cnt,x);sum+=x;
for(int k=;k<;++k)
{
int xx=i+dx[k];
int yy=j+dy[k];
if(pos[xx][yy])add(cnt,pos[xx][yy],INF);
}
}
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
int x=read();
add(++cnt,T,x);sum+=x;
for(int k=;k<;++k)
{
int xx=i+dx[k];
int yy=j+dy[k];
if(pos[xx][yy])add(pos[xx][yy],cnt,INF);
}
}
int flow=;while(bfs())while((flow=dinic(S,INF)))maxflow+=flow;
printf("%d\n",sum-maxflow);
return ;
}
luogu 3749 最大权闭合子图 我很迷的写完了。
//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db double
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=,maxn=MAXN*MAXN<<;
int n,m,cnt,t,h,S,T,maxflow,sum,len=;
int a[MAXN][MAXN],pos[MAXN][MAXN];
int b[MAXN],vis[maxn],q[maxn];
int lin[maxn],ver[maxn],nex[maxn],e[maxn];
inline void add(int x,int y,int z)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=;
}
inline int bfs()
{
memset(vis,,sizeof(vis));
h=t=;q[++t]=S;vis[S]=;
while(h++<t)
{
int x=q[h];
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!e[i]||vis[tn])continue;
q[++t]=tn;vis[tn]=vis[x]+;
if(tn==T)return ;
}
}
return ;
}
inline int dinic(int x,int flow)
{
if(x==T)return flow;
int rest=flow,k;
for(int i=lin[x];i&&rest;i=nex[i])
{
int tn=ver[i];
if(vis[tn]==vis[x]+&&e[i])
{
k=dinic(tn,min(e[i],rest));
if(!k){vis[tn]=;continue;}
e[i]-=k;e[i^]+=k;rest-=k;
}
}
return flow-rest;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(int i=;i<=n;++i)b[i]=read();
for(int i=;i<=n;++i)
for(int j=i;j<=n;++j)a[i][j]=read(),pos[i][j]=++cnt;
S=cnt+;T=S+;cnt=T;
for(int i=;i<=n;++i)
for(int j=i;j<=n;++j)
{
if(i==j)
{
a[i][j]-=b[i];
if(a[i][j]<)add(pos[i][j],T,-a[i][j]);
else add(S,pos[i][j],a[i][j]),sum+=a[i][j];
continue;
}
if(a[i][j]<)
{
add(pos[i][j],T,-a[i][j]);
add(pos[i][j],pos[i+][j],INF);
add(pos[i][j],pos[i][j-],INF);
}
else
{
sum+=a[i][j];
add(S,pos[i][j],a[i][j]);
add(pos[i][j],pos[i+][j],INF);
add(pos[i][j],pos[i][j-],INF);
}
}
for(int i=;i<=n;++i)
{
if(!vis[b[i]])
{
vis[b[i]]=++cnt;
add(vis[b[i]],T,m*b[i]*b[i]);
}
add(pos[i][i],vis[b[i]],INF);
//cout<<pos[i][i]<<' '<<vis[b[i]]<<endl;
}
int flow=;
while(bfs())while((flow=dinic(S,INF)))maxflow+=flow;
printf("%d\n",max(,sum-maxflow));
return ;
}
迷的地方在这里 如果一个组合权值为负 那么是这样连边:
而并非这样:
理由是 我选择了 l r 必须选择 l+1,r 和 r-1,l 这是必要的 第二种连边体现不出来这个特点故是错误的。
最大密度子图 01分数规划后转 最大权闭合子图即可。
//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db long double
#define EPS 1e-8
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
inline void put(int x)
{
x<?x=-x,putchar('-'):;
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=,maxn=*;
int n,m,S,T,ans,t,h,len=;
struct wy
{
int x,y;
}s[maxn];
int vis[maxn],q[maxn];
int lin[maxn],ver[maxn],nex[maxn];
db e[maxn];
inline void add(int x,int y,db z)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=;
}
inline int bfs()
{
memset(vis,,sizeof(vis));
t=h=;q[++t]=S;vis[S]=;
while(h++<t)
{
int x=q[h];
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(vis[tn])continue;
if(e[i]<=EPS)continue;
q[++t]=tn;vis[tn]=vis[x]+;
if(tn==T)return ;
}
}
return ;
}
inline db dfs(int x,db flow)
{
if(x==T)return flow;
db rest=flow,k;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(rest<=EPS)continue;
if(vis[tn]==vis[x]+)
{
if(e[i]<=EPS)continue;
k=dfs(tn,min(e[i],rest));
if(k<=EPS)vis[tn]=;
e[i]-=k;e[i^]+=k;
rest-=k;
}
}
return flow-rest;
}
inline db dinic()
{
db flow=,maxflow=;
while(bfs())while((flow=dfs(S,INF)))maxflow+=flow;
return maxflow;
}
inline db check(db w)
{
len=;
memset(lin,,sizeof(lin));
for(int i=;i<=m;++i)add(S,i,),add(i,s[i].x+m,INF),add(i,s[i].y+m,INF);
for(int i=;i<=n;++i)add(i+m,T,w);
return (db)m-dinic();
}
inline void dfs(int x)
{
vis[x]=;
if(x>m&&x<=n+m)++ans;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(e[i]>EPS&&!vis[tn])dfs(tn);
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
if(!m){puts("");return ;}
S=n+m+;T=S+;
for(int i=;i<=m;++i)
{
int x,y;
x=read();y=read();
s[i]=(wy){x,y};
}
db l=0.49,r=(db)m/2.0,eps=(1.0/n)/n;
while(l+eps<r)
{
db mid=(l+r)*0.5;
if(check(mid)>EPS)l=mid;
else r=mid;
}
check(l);
memset(vis,,sizeof(vis));
dfs(S);
printf("%d\n",ans);
return ;
}
费用流:
bzoj4514 还算比较简单 搞成二分图 注意快速连边的方法即可。
//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 100000000000000000ll
#define inf 1000000000
#define ll long long
#define min(x,y) (x>y?y:x)
#define max(x,y) (x>y?x:y)
#define RI register long long
#define up(p,i,n) for(int i=p;i<=n;++i)
#define db double
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
int x=,f=;char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
//啊 自闭了 写发SDOI找回自信。。
//SDOI 2016 数字配对。
//一个数字是ai 有bi个 权值是ci
//当且仅当ai/aj是质数 两个数字可以配对 显然是最大费用最大流!
//考虑如何建图 显然的是这是一张二分图建一张即可。注意开ll
const int MAXN=*;
int n,len=,h,t,T,S;
int a[MAXN],b[MAXN],w[MAXN],in[MAXN];
int q[MAXN],pre[MAXN],vis[MAXN],f[MAXN];
ll dis[MAXN],sum,e1[MAXN<<],maxflow,c[MAXN];
int lin[MAXN],ver[MAXN<<],nex[MAXN<<],e[MAXN<<];
inline void add(int x,int y,int z,ll z1)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;e1[len]=z1;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=;e1[len]=-z1;
}
inline void transform(int x)
{
int w=a[x],cnt=;
for(int i=;i*i<=a[x];++i)
while(w%i==)
{
w/=i;
++cnt;
}
if(w>)++cnt;
f[x]=cnt;
}
inline int spfa()//最大费用最大流
{
for(int i=;i<=T;++i)dis[i]=-INF;
t=h=;dis[S]=;q[++t]=S;vis[S]=;in[S]=inf;
while(h++<t)
{
int x=q[h];vis[x]=;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
if(!e[i])continue;
if(dis[tn]<dis[x]+e1[i])
{
dis[tn]=dis[x]+e1[i];
in[tn]=min(in[x],e[i]);
pre[tn]=i;
if(!vis[tn])q[++t]=tn,vis[tn]=;
}
}
}
return dis[T]!=-INF;
}
inline void EK()
{
while(spfa())
{
int x=T,i=pre[x];
if(sum+in[T]*dis[T]<)
{
maxflow+=sum/(-dis[T]);
break;
}
sum+=in[T]*dis[T];
maxflow+=in[T];
while(x!=S)
{
e[i]-=in[T];
e[i^]+=in[T];
x=ver[i^];i=pre[x];
}
}
}
int main()
{
//freopen("1.in","r",stdin);
n=read();S=n+;T=S+;
for(int i=;i<=n;++i)a[i]=read(),transform(i);
for(int i=;i<=n;++i)b[i]=read();
for(int i=;i<=n;++i)c[i]=read();
for(int i=;i<=n;++i)
if(f[i]&)for(int j=;j<=n;++j)
if(((f[i]==f[j]+)&&(a[i]%a[j]==))||((f[i]==f[j]-&&a[j]%a[i]==)))
add(i,j,inf,c[i]*c[j]);
for(int i=;i<=n;++i)
if(f[i]&)add(S,i,b[i],);
else add(i,T,b[i],);
EK();
printf("%lld\n",maxflow);
return ;
}
2019 HL SC day2的更多相关文章
- 2019 HL SC day1
今天讲的是图论大体上分为:有向图的强连通分量,有向图的完全图:竞赛图,无向图的的割点,割边,点双联通分量,变双联通分量以及圆方树 2-sat问题 支配树等等. 大体上都知道是些什么东西 但是仍需要写一 ...
- 2019 HL SC day10
10天都过去了 4天都在全程懵逼.. 怎么可以这么难啊 我服了 现在想起依稀只记得一些结论 什么 反演? 什么后缀自动机?什么组合数的应用?什么神仙东西 ,不过讲课人的确都是神仙.(实名羡慕. mzx ...
- 2019 HL SC day4
自闭场本来 以为 顶多一些不太会 结果发现 一堆不太会 . 树状数组 感觉 好久没看 了有点遗忘 不过还好 现在我来了.莅临之神将会消灭一切知识点哦. 今天说点不一样东西 树状数组 hh 很有用的东 ...
- 刷题记录:[CISCN2019 东北赛区 Day2 Web3]Point System
目录 刷题记录:[CISCN2019 东北赛区 Day2 Web3]Point System 知识点 1.padding-oracle attack 2.cbc字节翻转攻击 3.FFMpeg文件读取漏 ...
- Solr分组查询
项目中需要实时的返回一下统计的东西,因此就要进行分组,在获取一些东西,代码拿不出来,因此分享一篇,还是很使用的. facet搜索 /** * * 搜索功能优化-关键词搜索 * 搜索范围:商品名称.店 ...
- Light of future-冲刺集合
table th:nth-of-type(1) { width: 85px; } table th:nth-of-type(2){ width: 80px; } table th:nth-of-typ ...
- Light of future-冲刺总结
目录 1.凡事预则立.测试博客的链接 2.包含冲刺日志集合随笔的所有内容 3.描述项目预期计划 7.代码仓库地址.测试文档链接地址.PPT链接地址 归属班级 →2019秋福大软件工程实践Z班 作业要求 ...
- 【LOJ】#3034. 「JOISC 2019 Day2」两道料理
LOJ#3034. 「JOISC 2019 Day2」两道料理 找出最大的\(y_{i}\)使得\(sumA_{i} + sumB_{y_i} \leq S_{i}\) 和最大的\(x_{j}\)使得 ...
- 【LOJ】#3033. 「JOISC 2019 Day2」两个天线
LOJ#3033. 「JOISC 2019 Day2」两个天线 用后面的天线更新前面的天线,线段树上存历史版本的最大值 也就是线段树需要维护历史版本的最大值,后面的天线的标记中最大的那个和最小的那个, ...
随机推荐
- 「疫期集训day1」无言
正式集训第一天,感觉没啥特别大的感受,无非是奥赛时间延长了,效率提高了,身外事少了 当然不止这些 感受1:有些曾经被恶的题现在仍然在恶心,例如昨天的farmcraft,今天的整数划分(和着多边形一块调 ...
- unity spine 对翻转和大小的控制
spine-unity怎么决定我的Spine模型的大小? Spine使用 1像素:1单位.意思是,如果你只是包含图像在你的骨架中,并且没有任何旋转和缩放,在Spine中该图像的1个像素就对应1个单位高 ...
- 查看mysql所有命令
- PHP使用array_filter查找二维数组中符合字段和字段值的数据集合
1.方法: /** * 获取符合字段和字段值的数组集合 * @param array $data 待过滤数组 * @param string $field 要查找的字段 * @param $value ...
- python虚拟环境 + 批量pip + 换源
python虚拟环境 + 批量pip + 换源 虚拟环境 曾经我是一个小白,不管运行什么项目都用一个环境,后来项目多了,有的是Django1.11的有的是Django2的,有的项目只能在3.6上运行, ...
- java 面向对象(四十三):反射(七)反射应用四:动态代理
1.代理模式的原理:使用一个代理将对象包装起来, 然后用该代理对象取代原始对象.任何对原始对象的调用都要通过代理.代理对象决定是否以及何时将方法调用转到原始对象上. 2.静态代理2.1 举例:实现Ru ...
- Python读取文件基本方法
在日常开发过程中,经常遇到需要读取配置文件,这边就涉及到一个文本读取的方法. 这篇文章主要以Python读取文本的基础方法为本,添加读取整篇文本返回字符串,读取键值对返回字典,以及读取各个项返回列表的 ...
- bzoj3062[Usaco2013 Feb]Taxi*
bzoj3062[Usaco2013 Feb]Taxi 题意: Bessie在农场上为其他奶牛提供出租车服务,她必须赶到这些奶牛的起始位置,并把他们带到它们的目的地.Bessie的车很小,所以她只能一 ...
- 集训作业 洛谷P1866 编号
这个题是个数学题啊. 总体思路不是很难,每个兔子有一个编号,只要不停的看下一个兔子有多少可选编号,再乘上之前的所有可能性就可以算出一共的编号方法. #include<iostream> # ...
- 设计模式:fly weight模式
目的:通过共享实例的方式来避免重复的对象被new出来,节约系统资源 别名:享元模式 例子: class Char //共享的类,轻量级 { char c; public: Char(char c) { ...