您的位置:首页 > 其它

[bzoj4514]数字配对[费用流]

2016-04-25 20:30 330 查看

今年SDOI的题,看到他们在做,看到过了一百多个人,然后就被虐惨啦。。。

果然考试的时候还是打不了高端算法,调了。。。几天

默默地yy了一个费用流构图:

源连所有点,配对的点连啊,所有点连汇。。。

后来罗爷爷提醒我这样子会wa,因为你无法保证所有点都没有超过B[I]次,too naive

正解是还要考虑到奇数/偶数个质数的数字,把它们变成可二分图,看出这个性质就OK了。。。

至于要保证费用下界的问题,这个。。我也不知道为什么我原来的方法不行

后来照着标程改的,加了一行memset就过了,一脸懵逼

又贡献了一道orzliyicheng没过的题,yeah~O(∩_∩)O

#include<cstdio>
#include<algorithm>
#include<cstring>
#define mo 200000
#define value pri
#define N 200000
#define vis flag
#define ll long long
#define inf 10000000000000LL
using namespace std;
ll maxn=34000,S,T,num,n,edgenum;
ll ans,tmp;
ll next
,head
,up
,flag
,vet
,pri
,from
,cost
,q
,dis
,a
,b
,c
,f
;
void add(int u,int v,ll w,ll c)
{
//printf("%d %d %lld %lld\n",u,v,w,c);
edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum;
pri[edgenum]=w;cost[edgenum]=c;from[edgenum]=u;
}
ll min(ll a,ll b)
{
if(a<b)return a;else return b;
}
bool spfa()
{
memset(dis,127,sizeof(dis));
memset(up,0,sizeof(up));
dis[S]=0;
vis[S]=1;
q[1]=S;
bool yes=0;int tou=1,tail=1;
while (tou<=tail)
{
int x=q[tou%mo];vis[x]=0;//printf("query=%d\n",x);
for (int i=head[x];i;i=next[i])
if (pri[i]&&dis[vet[i]]>dis[x]+cost[i])
{
//printf("vet=%d\n",vet[i]);
dis[vet[i]]=dis[x]+cost[i];
up[vet[i]]=i;
if (!vis[vet[i]]) vis[vet[i]]=1,tail++,q[tail%mo]=vet[i];//printf("tail=%d\n",tail);
if (vet[i]==T) yes=1;
}
tou++;
}
//for(int i=0;i<=T;i++)printf("%lld ",dis[i]);printf("\n");
if (!yes) return 0;
else return 1;
}
bool flow()
{
int minn=inf;
for (int i=up[T];i;i=up[from[i]])
minn=min(minn,pri[i]);
//printf("min==%lld %lld\n",dis[T],minn);
if (tmp+dis[T]*minn<=0)
{
for (int i=up[T];i;i=up[from[i]])
{
int ee=i+1;if(i%2==0)ee=i-1;
pri[i]-=minn;
pri[ee]+=minn;
}
ans+=minn;
tmp+=dis[T]*minn;
return 1;
}
else {ans-=(tmp/dis[T]);return 0;}
}
void dinic()
{
ans=0;tmp=0;
for(int i=0;i<=T;i++)flag[i]=0;
while (spfa()&&flow());
printf("%lld",ans);
}
ll calc(ll x)
{
ll ans=0;
for(int i=1;i<=num;i++)
while(x%pri[i]==0)
{
x/=pri[i];ans++;
}
if(x!=1)ans++;return ans;
}
int main()
{
freopen("4514.in","r",stdin);
freopen("4514.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
for(int i=1;i<=n;i++)scanf("%lld",&c[i]);
for(ll i=2;i<=maxn;i++)
{
if(flag[i]==0)num++,pri[num]=i;
for(int j=1;j<=num;j++)
{
if(pri[j]*i>maxn)break;
flag[pri[j]*i]=1;
if(i%pri[j]==0)break;
}
}
for(int i=1;i<=n;i++)f[i]=calc(a[i]);
S=n+1,T=n+2;
for(int i=1;i<=n;i++)
if(f[i]%2==1)add(S,i,b[i],0),add(i,S,0,0);else add(i,T,b[i],0),add(T,i,0,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i]%a[j]==0)if(f[i]==f[j]+1)
{
int u,v;
if(f[i]%2==1)u=i;else u=j;if(f[i]%2==0)v=i;else v=j;
add(u,v,inf,-c[i]*c[j]);//printf("%d %d\n",c[i],c[j]);
add(v,u,0,c[i]*c[j]);
}
dinic();
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: