bzoj 3308: 九月的咖啡店(最大费用最大流)

3308: 九月的咖啡店

Time Limit: 30 Sec   Memory Limit: 128 MB
Submit: 278   Solved: 100
[ Submit][ Status][ Discuss]

Description

深绘里在九份开了一家咖啡让,如何调配咖啡民了她每天的头等大事
我们假设她有N种原料,第i种原料编号为i,调配一杯咖啡则需要在这
里若干种兑在一起。不过有些原料不能同时在一杯中,如果两个编号
为i,j的原料,当且仅当i与j互质时,才能兑在同一杯中。
现在想知道,如果用这N种原料来调同一杯咖啡,使用的原料编号之和
最大可为多少。

Input

一个数字N

Output

如题

Sample Input

10

Sample Output

30


zkw网络流不会写,强行加了个SPFA,感觉更慢了

这题很难想到呀,一开始以为就是所有只含有一个质因子且尽可能大的数加在一起,

比如n=200000的时候,找到所有小于200000的质数并将它们一个一个不停地次方直到无限接近于n然后加在一起就好了,但这样不一定最大,有可能可以包含两个质因子!而现实就是,能达到最优的配料编号一定最多只含有两个质因子,且一个小于sqrt(n),另一个大于sqrt(n)

既然这样还是好办

因为小于sqrt(n)的个数非常少,不超过100个,那么可以建张图:

所有小于sqrt(n)的质数与源点连接一条流量为1,费用为0的边

所有大于sqrt(n)的质数与汇点连接一条流量为1,费用为0的边

所有小于sqrt(n)的质数和大于sqrt(n)的质数连接一条流量为1,费用为Vab-Va-Vb的边

其中Va = a^(lgn/lga),Vb = b,Vab = a^(lg(n/b)/lga)*b

如果这个费用小于0则直接不连边就好,最后答案就是最大费用最大流+①情况的值


#include
#include
#include
using namespace std;
#define LL long long
typedef struct Res
{
	int next;
	int to, from;
	int flow, cost;
}Road;
Road G[2000005];
int head[200010], vis[200010], dis[200010], pri[200010], flag[200010] = {1,1}, S, T, cnt, n, ans; 
void Add(int u, int v, int flow, int cost)
{
	cnt++;
	G[cnt].next = head[u];
	head[u] = cnt;
	G[cnt].from = u;
	G[cnt].to = v;
	G[cnt].flow = flow;
	G[cnt].cost = cost;
}
int SPFA()
{
	int now, i, v;
	queue q;
	memset(vis, 0, sizeof(vis));
	memset(dis, -62, sizeof(dis));					//如果是求最小费用,初始化应该为很大的正数,下同
	q.push(S);
	vis[S] = 1;
	dis[S] = 0;
	while(q.empty()==0)
	{
		now = q.front();
		q.pop();
		vis[now] = 0;
		for(i=head[now];i!=0;i=G[i].next)
		{
			v = G[i].to;
			if(G[i].flow && dis[v]dis[now]+G[i].cost
			{
				dis[v] = dis[now]+G[i].cost;
				if(vis[v]==0)
				{
					vis[v] = 1,
					q.push(v);
				}
			}
		}
	}
	if(dis[T]>0)				//如果是求最小费用,这里改成dis[T]=n/2)
		{
			ans += pri[i];
			continue;
		}
		if((LL)pri[i]*pri[i]<=n)
		{
			Add(S, i, 1, 0);
			Add(i, S, 0, 0);
			ans += Jud(n, pri[i]);
			pos = i;
		}
		else
		{
			Add(i, T, 1, 0);
			Add(T, i, 0, 0);
			ans += pri[i];
		}
	}
	for(i=1;i<=pos;i++)
	{
		for(j=pos+1;j<=sum;j++)
		{
			if((LL)pri[i]*pri[j]>n)
				break;
			temp = Jud(n/pri[j], pri[i])*pri[j]-Jud(n, pri[i])-pri[j];
			if(temp>0)
			{
				Add(i, j, 1, temp);
				Add(j, i, 0, -temp);
			}
		}
	} 
	while(SPFA()) 
	{
		memset(vis, 0, sizeof(vis));
		while(Sech(S, -1000000000))
			memset(vis, 0, sizeof(vis));
	}
	printf("%d\n", ans+1);
	return 0;
}

你可能感兴趣的:(网络流)