zoukankan      html  css  js  c++  java
  • P4068 [SDOI2016]数字配对

     https://www.luogu.com.cn/problem/P4068

    质因数分解然后建立二分图,跑费用流

    具体看第一个官方题解的代码就好了,我想说的是费用流控制流量使得费用大于0且流量最大的方法,具体看代码,受益匪浅

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    
    const ll inf = 1e16;
    const int maxn = 1005;
    const int M = 1005;
    
    queue<int> que;
    int head[maxn];
    struct Edge{
    	int id,nex;
    	ll w,f;
    }edge[M<<1];
    
    int cnt = 0;
    
    void init(){
    	cnt=0;
    	memset(head,-1,sizeof(head));
    	while(que.size()) que.pop();
    	
    }
    
    void add_(int x,int y,ll f,ll w){
    	edge[cnt].id = y;
    	edge[cnt].f = f;
    	edge[cnt].w = w;
    	edge[cnt].nex = head[x];
    	head[x] = cnt ++ ;
    }
    
    void add(int x,int y,ll f,ll w){
    	add_(x,y,f,w);
    	add_(y,x,0,-w);
    }
    
    int n,m;
    
    
    int vis[maxn];
    ll dis[maxn];
    ll mflow[maxn];
    int per[maxn];
    
    
    
    int spfa(int s,int t){
    	for (int i = 0; i<= n+16 ; i++ ){
    		vis[i] = 0;
    		dis[i] = inf;
    	}
    	
    	 
    	mflow[s] = inf;
    	que.push(s);
    	dis[s] = 0;
    	vis[s] = 1;
    	
    	while(que.size()){
    		int x=  que.front();
    		que.pop();
    		vis[x] = 0;
    		for (int i = head[x]; ~i; i = edge[i].nex){
    			int v = edge[i].id;
    			if(dis[v] > dis[x] + edge[i].w && edge[i].f){
    				dis[v] = dis[x] + edge[i].w;
    				per[v] = i;
    				mflow[v] = min(mflow[x],edge[i].f);
    				if(vis[v])	continue;
    				
    				vis[v] = 1;
    				que.push(v);
    			}
    		}
    	}
    	if(dis[t] != inf)	return 1;
    	else return 0;
    }
    ///!!!!!!!
    
    void update(int s,int t, ll& flow){
    	ll minn = mflow[t];
    	for (int i = t; i != s; i = edge[per[i] ^ 1].id){//沿着路走 
    		
    		int x = per[i];
    		edge[x].f -= minn;
    		edge[x^1].f += minn;
    	}
    	flow += minn;
    }
    int len = 0;
    ll solve(int s,int t, ll& flow){
    	ll ans = 0;
    	len = 0;
    	while(spfa(s,t)){//鐢╯pfa寮€璺?
    		if(ans + dis[t] * mflow[t] > 0){
    			
    			flow -= ans/dis[t]; 
    			return ans;
    		}
    		ans += dis[t] * mflow[t];
    		update(s,t,flow);
    	}
    	return ans;
    }
    //----------------------------------------------------------------------------------------
    //以上是网络流模板
    const int Maxn = 1e5+7;
    int prime[Maxn];
    int Mark[Maxn+1];
     
    int sieve() {
     
        int p = 0;
     
        Mark[0] = 1; Mark[1] = 1;
        for (int i = 2; i < Maxn; i++){
            if (Mark[i] == 0) {
                prime[p++] = i;
            }
            for (int j = 0; j < p && prime[j] * i < Maxn; j++){
                Mark[i * prime[j]] = 1;
                if (i % prime[j] == 0) {
                    break;
                }
            }
        }
        return p;
    }
    
    int chal;
     
    ll a[maxn],b[maxn],c[maxn];
    int ans[maxn];
    
    int cal(int x){
    	int cns = 0;
    	for(int i = 2;1LL*i*i<= x;i++){
    		while(x % i == 0){
    			x /= i;
    			cns++;
    		}
    	}
    	if(x > 1 ) cns ++;
    	return cns;
    }
    
    
    
    int main(){ 
    
    	init();
    	scanf("%d",&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(int i=1;i<=n;i++){
    		ans[i] = cal(a[i]);//有几个质数因子 
    	}
    	
    	for(int i=1;i<=n;i++){
    		if(ans[i] & 1 ){
    			
    			for(int j=1;j<=n;j++){
    				if(ans[j] %2 == 0 ){
    					if(a[i] % a[j] == 0 && ans[j] + 1 == ans[i]){
    						add(i,j,inf,-1LL*c[i]*c[j]);
    					}
    					else if(a[j] % a[i] == 0 && ans[i] + 1== ans[j] ){
    						add(i,j,inf,-1LL*c[i]*c[j]);
    					}
    				}
    			}	
    		}
    	}
    	int s,t;
    	
    	s = 0;
    	t = n+11;
    	for(int i=1;i<=n;i++){
    		if(ans[i] & 1){
    			add(s,i,b[i],0);
    //			cout<<s<<" "<<i<<" "<<b[i]<<endl;
    		}
    		else{
    			add(i,t,b[i],0);
    //			cout<<i<<" "<<t<<" "<<b[i]<<endl;
    		}
    	}
    	ll f = 0;
    	ll cc = solve(s,t,f);
    	printf("%lld
    ",f);
    }
    /*
    
    3
    2 4 8
    2 200 7
    -1 -2 1
    4
    
    
    */
    

      

    寻找真正的热爱
  • 相关阅读:
    Netty实战
    ObjectTools反射实例
    SpringBoot新增监听器Listener
    拦截器(Inteceptor),过滤器(Filter),切面(Aspect)处理HttpServiceReqeust请求
    Linux CentOS7.2下安装Redis && 配置Redis开机自启动
    JVM命令行工具&垃圾收集器&垃圾收集策略思维导图
    Redis总结
    Java自定义注解的实现
    反射实例
    系统管理员常用的Linux命令
  • 原文地址:https://www.cnblogs.com/lesning/p/13710546.html
Copyright © 2011-2022 走看看