• [SDOI2016]数字配对


    \(Solution\)

    考虑\(a_i\)的限制,设\(a_i = \prod {p_i^{k_i}},s_i = \sum{k_i}\)
    对于条件,当且仅当\(a_j | a_i\)\(s_i = s_j + 1\),以\(s_i\)的奇偶分为两个集合,发现是一个二分图,\(b_i\)则为流量,而对于权值大于\(0\)的限制,做完单源增广路后,改变流量即可。

    \(Code\)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    using namespace std;
    const int inf = 2147483647;
    int n,S,T,a[205],b[205],h[205],p[100005],vis[100005],cnt,tot = 1,pre[205];
    int viss[205],up[205],flow[205],q[2000005],s[205];
    LL dis[205],c[205];
    
    struct edge{
    	int to,nxt,flw;
    	LL v;
    }e[1000005];
    void add(int x,int y,int z,LL z2)
    {
    	e[++tot] = edge{y,h[x],z,z2},h[x] = tot;
    	e[++tot] = edge{x,h[y],0,-z2},h[y] = tot;
    }
    void init()
    {
    	for (int i = 2; i <= 100000; i++)
    	{
    		if (!vis[i]) p[++cnt] = i;
    		for (int j = 1; j <= cnt && i * p[j] <= 100000; j++)
    		{
    			vis[p[j] * i] = 1;
    			if (i % p[j] == 0) break;
    		}
    	}
    }
    int spfa()
    {
    	for (int i = 0; i <= 204; i++) dis[i] = -1e18;
    	memset(viss,0,sizeof vis);
    	memset(flow,127,sizeof flow);
    	int head = 0,tail = 1;
    	q[1] = S,dis[S] = 0,vis[S] = 1,pre[T] = -1;
    	while (head < tail)
    	{
    		int u = q[++head]; viss[u] = 0;
    		for (int i = h[u]; i; i = e[i].nxt)
    		{
    			int v = e[i].to;
    			if (dis[v] < dis[u] + e[i].v && e[i].flw > 0)
    			{
    				dis[v] = dis[u] + e[i].v,pre[v] = u,up[v] = i;
    				flow[v] = min(flow[u],e[i].flw);
    				if (!viss[v]) viss[v] = 1,q[++tail] = v;
    			}
    		}
    	}
    	return (pre[T] == -1 ? 0 : 1);
    }
    int main()
    {
    	init();
    	scanf("%d",&n),S = n + 1,T = S + 1;
    	for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
    	for (int i = 1; i <= n; i++) scanf("%d",&b[i]);
    	for (int i = 1; i <= n; i++) scanf("%lld",&c[i]);
    	for (int i = 1; i <= n; i++)
    	{
    		int g = a[i];
    		for (int j = 1; j <= cnt && g > 1; j++)
    			while (g % p[j] == 0) g /= p[j],s[i]++;
    		if (g > 1) s[i]++;
    		if (s[i] & 1) add(S,i,b[i],0);
    		else add(i,T,b[i],0);
    	}
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= n; j++)
    			if (a[i] % a[j] == 0 && i != j && s[i] == s[j] + 1)
    			{
    				if (s[i] & 1) add(i,j,inf,c[i] * c[j]);
    				else add(j,i,inf,c[i] * c[j]);
    			}
    	int al = 0; LL av = 0;
    	while (spfa())
    	{
    		int o = T,F,k;
    		if (dis[T] == 0) k = 0;
    		else k = av / dis[T];
    		if (dis[T] >= 0) F = flow[T];
    		else F = min(flow[T],abs(k));
    		if (F == 0) break;
    		al += F,av += (LL)dis[T] * F;
    		for (; o != S; o = pre[o]) e[up[o]].flw -= F,e[up[o] ^ 1].flw += F;
    	}
    	printf("%d\n",al);
    }
    
  • 相关阅读:
    mysql 查询重复 去除重复等等
    css 控制行数 多出的省略
    php修改SESSION的有效生存时间
    php 冒泡排序
    spring---------配置文件的命名空间
    POM(project Object Model) Maven包管理依赖 pom.xml文件
    输入一个网站地址到网站展现的过程以及APR协议(鬼知道中间经历了什么)
    Apache CXF 入门详解
    Python中协程Event()函数
    Scikit Learn安装教程
  • 原文地址:https://www.cnblogs.com/nibabadeboke/p/15828094.html
Copyright © 2020-2023  润新知