• SDOI2016数字配对


    网络流算法基于贪心


    很容易想到最大费用最大流,但我们无法保证费用是非负的

    因为每次的最长路都是在逐渐变小的,所以可以贪心

    (dfs)是先不加费用,完了后根据流量看费用是否非负,如果变负数就贪心选尽可能多的的对数,不然继续

    可以看(mcmf)函数,一下就明白了

    小技巧:(cn_i)(a_i)质因数分解后,每个质因数的指数和,只可能是相差为1的连边,所以是个二分图,根据每个点(cn_i)的奇偶性判断连起点或终点

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    const int N=204,inf=1e18;
    bitset<40004>bb;
    int n,tot,s,t;
    int pri[5000],a[N],b[N],c[N],cn[N],vis[N],dis[N];
    inline void init(){
    	for(int i=2;i<=40000;i++){
    		if(!bb[i])pri[++tot]=i;
    		for(int j=1;j<=tot&&pri[j]*i<=40000;j++){
    			bb[pri[j]*i]=1;
    			if(i%pri[j]==0)break;
    		}
    	}
    }
    struct edge{
    	int v,c,f,nxt;
    }e[N*N*2];
    int first[N],cur[N],cnt=1;
    inline void add(int u,int v,int c,int f){
    	e[++cnt]=(edge){v,c,f,first[u]};
    	first[u]=cnt;
    	e[++cnt]=(edge){u,-c,0,first[v]};
    	first[v]=cnt;
    }
    inline bool spfa(){
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<=t;i++)dis[i]=-inf;
    	static queue<int>q;
    	q.push(t);dis[t]=0;vis[t]=1; 
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		vis[x]=0;
    		for(int i=first[x],v;i;i=e[i].nxt){
    			v=e[i].v;
    			if(e[i^1].f&&dis[v]<dis[x]-e[i].c){
    				dis[v]=dis[x]-e[i].c;
    				if(!vis[v]){q.push(v);vis[v]=1;}
    			}
    		}
    	}
    	return dis[s]!=-inf;
    }
    int dfs(int x,int f){
    	if(!f)return 0;
    	if(x==t){vis[0]=1;return f;}
    	vis[x]=1;
    	int used=0;
    	for(int &i=cur[x],v,w;i;i=e[i].nxt){
    		v=e[i].v;
    		if(vis[v]||!e[i].f||dis[v]+e[i].c!=dis[x])continue;
    		w=dfs(v,min(f,e[i].f));
    		if(!w)continue;
    		e[i].f-=w;e[i^1].f+=w;
    		f-=w;used+=w;
    		if(!f)break;
    	}
    	return used;
    }
    inline int mcmf(){
    	int flow,ret=0,cost=0;
    	while(spfa()){
    		memcpy(cur,first,sizeof(first));
    		vis[0]=1;
    		while(vis[0]){
    			memset(vis,0,sizeof(vis));
    			flow=dfs(s,inf);
    			if(cost+flow*dis[s]>=0){
    				cost+=flow*dis[s];
    				ret+=flow;
    			}
    			else return ret+cost/(-dis[s]);
    		}
    	}
    	return ret;
    }
    signed main(){
    	init();
    	n=read();s=n+1;t=s+1; 
    	for(int i=1,x;i<=n;i++){
    		a[i]=x=read();
    		for(int j=1;j<=tot&&pri[j]*pri[j]<=a[i];j++)
    			while(x%pri[j]==0){
    				x/=pri[j];
    				cn[i]++;
    			}
    		if(x>1)cn[i]++;
    	} 
    	for(int i=1;i<=n;i++){
    		b[i]=read();
    		if(cn[i]&1)add(s,i,0,b[i]);
    		else add(i,t,0,b[i]);
    	}
    	for(int i=1;i<=n;i++)c[i]=read();
    	for(int i=1;i<=n;i++){
    		if(!(cn[i]&1))continue;
    		for(int j=1;j<=n;j++){
    			if(cn[j]&1)continue;
    			if((a[i]%a[j]==0&&cn[i]==cn[j]+1)||(a[j]%a[i]==0&&cn[i]==cn[j]-1))
    				add(i,j,c[i]*c[j],min(b[i],b[j]));
    		}
    	}
    	cout<<mcmf();
    	return (0-0);
    }
    
  • 相关阅读:
    Thinkphp3.2 cms之角色开发
    说几个你知道的设计模式?
    9种实现点击一个链接弹出一个小窗口的代码
    分享自己作为一个程序员的找工作经历
    网页设置锚点
    博客园网摘地址
    PHP面试总结
    简单的10秒倒计时
    PHP测试题目
    关键字搜索内容总结
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12557796.html
Copyright © 2020-2023  润新知