【BZOJ-3308】九月的咖啡店 最大费用最大流 + 线性筛素数
3308: 九月的咖啡店
Time Limit: 30 Sec Memory Limit: 128 MB
Submit:
159 Solved: 56
[Submit][Status][Discuss]
Description
深绘里在九份开了一家咖啡让,如何调配咖啡民了她每天的头等大事我们假设她有N种原料,第i种原料编号为i,调配一杯咖啡则需要在这里若干种兑在一起。不过有些原料不能同时在一杯中,如果两个编号为i,j的原料,当且仅当i与j互质时,才能兑在同一杯中。现在想知道,如果用这N种原料来调同一杯咖啡,使用的原料编号之和最大可为多少。
Input
一个数字N
Output
如题
Sample Input
Sample Output
HINT
1<=N<=200000
Source
Solution
从N的范围,难以直接看出是网络流,但仔细分析,还是可以想到的
比较厉害的建图,首先需要两个结论:
1.一个数的质因子,最多有两个
2.并且这两个质因子,一个小于$\sqrt{n}$,一个大于$\sqrt{n}$
那么可以考虑筛出1~n的素数
考虑建二分图
源向小于$\sqrt{n}$的质数连边,容量为1,费用为0
大于$\sqrt{n}$的质数向汇连边,容量为1,费用为0
小于$\sqrt{n}$的质数$a$向大于$\sqrt{n}$的质数$b$连边,容量为1,费用为$V_{ab}-V_{a}-V_{b}$
$V_{a}$表示单独选$a$的最大收益$V_{a}=a^{lgn/lga}$
$V_{b}$表示单独选$b$的最大收益$V_{b}=b$
$V_{ab}$表示同时选$a$和$b$的最大收益$V_{ab}=a^{lg(n/b)/lga}*b$
这样效率并不是特别的高,那么还可以加上两个优化:
1.如果一个质数>n/2,那么它只能单独选,不用连边
2.如果一条边的费用<0,那么完全可以不连
然后考虑 最大费用最大流 即可
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; char ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 200010
#define maxm 200000*10+10
#define inf 0x7fffffff
int n,ans;
struct Edgenode{int next,to,from,cap,cost;}edge[maxm];
int head[maxn],cnt=;
//init
inline void add(int u,int v,int w,int c)
{
cnt++; edge[cnt].next=head[u]; head[u]=cnt;
edge[cnt].from=u; edge[cnt].to=v; edge[cnt].cap=w; edge[cnt].cost=c;
}
inline void insert(int u,int v,int w,int c)
{add(u,v,w,c); add(v,u,,-c);}
//addedge
bool mark[maxn];int dis[maxn],S,T;
inline bool spfa()
{
queue<int>q; memset(mark,,sizeof(mark));
for (int i=S; i<=T; i++) dis[i]=-inf;
q.push(S); mark[S]=; dis[S]=;
while (!q.empty())
{
int now=q.front(); q.pop();
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].cap && dis[edge[i].to]<dis[now]+edge[i].cost)
{
dis[edge[i].to]=dis[now]+edge[i].cost;
if (!mark[edge[i].to])
mark[edge[i].to]=,q.push(edge[i].to);
}
mark[now]=;
}
return dis[T]>;
}
inline int dfs(int loc,int low)
{
mark[loc]=;
if (loc==T) return low;
int w,used=;
for (int i=head[loc]; i; i=edge[i].next)
if (edge[i].cap && dis[edge[i].to]==dis[loc]+edge[i].cost && !mark[edge[i].to])
{
w=dfs(edge[i].to,min(low-used,edge[i].cap));
edge[i].cap-=w; edge[i^].cap+=w; used+=w;
ans+=w*edge[i].cost; if (used==low) return low;
}
return used;
}
inline void zkw()
{
int tmp=;
while (spfa())
{
mark[T]=;
while (mark[T])
memset(mark,,sizeof(mark)),tmp+=dfs(S,inf);
}
}
//MaxflowMaxcost
bool flag[maxn]; int prime[maxn],tot;
inline void prework(int maxx)
{
flag[]=;
for (int i=; i<=maxx; i++)
{
if (!flag[i]) prime[++tot]=i;
for (int j=; j<=tot && i*prime[j]<=maxx; j++)
{
flag[i*prime[j]]=;
if (!(i%prime[j])) break;
}
}
}
//get prime
inline int calc(int n,int x)
{
long long t=x;
while (t*x<=n) t=t*x;
return t;
}
//calc
inline void make()
{
S=,T=tot+; int pos=;
for (int i=; i<=tot; i++)
{
if (prime[i]>=n/) {ans+=prime[i];continue;}
if ((long long)prime[i]*prime[i]<=n)
insert(S,i,,),ans+=calc(n,prime[i]);
else
pos=(!pos)?i:pos,insert(i,T,,),ans+=prime[i];
}
for (int i=; i<pos; i++)
for (int j=pos; j<=tot; j++)
{
if ((long long)prime[i]*prime[j]>n) break;
int tmp=calc(n/prime[j],prime[i])*prime[j]-calc(n,prime[i])-prime[j];
if (tmp>) insert(i,j,,tmp);
}
}
//build
int main()
{
n=read();
prework(n);
make();
zkw();
printf("%d\n",ans+);
return ;
}
忽略桑心病狂的inline.. && 自己YY的最大费用最大流...好像还可以?
【BZOJ-3308】九月的咖啡店 最大费用最大流 + 线性筛素数的更多相关文章
- 【BZOJ 3308】 3308: 九月的咖啡店 (费用流|二分图最大权匹配)
3308: 九月的咖啡店 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 244 Solved: 86 Description 深绘里在九份开了一家咖 ...
- bzoj 3308: 九月的咖啡店【最大费用最大流】
费用流里spfa最后的判断要写成dis[t]>=0而不是dis[t]!=-inf否则会WAWAWA-- #include<iostream> #include<cstdio&g ...
- bzoj 3308 九月的咖啡店
题目大意: 求若干个<=n的数 两两互质 使和最大 求这个最大的和 思路: 显然,得到两个结论 1 最终的所有数都只能分解为两个质因数 2 这两个质因数 一个<根号n 一个>根号n ...
- BZOJ 2668 [cqoi2012]交换棋子 | 最小费用最大流
传送门 BZOJ 2668 题解 同时分别限制流入和流出次数,所以把一个点拆成三个:入点in(x).中间点mi(x).出点ou(x). 如果一个格子x在初始状态是黑点,则连(S, mi(x), 1, ...
- BZOJ 1061 志愿者招募(最小费用最大流)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1061 题意:申奥成功后,布布经过不懈努力,终于 成为奥组委下属公司人力资源部门的主管.布 ...
- bzoj 1070 [SCOI2007]修车(最小费用最大流)
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3515 Solved: 1411[Submit][Status] ...
- BZOJ 1221: [HNOI2001] 软件开发(最小费用最大流)
不知道为什么这么慢.... 费用流,拆点.... --------------------------------------------------------------------------- ...
- bzoj 3171: [Tjoi2013]循环格 最小费用最大流
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3171 题解: 首先我们很容易发现一个结论: 出现完美循环当且仅当所有点的出入度均为1 所 ...
- bzoj 1070: [SCOI2007]修车【最小费用最大流】
一开始从客人角度想的,怎么建都不对 从一个修车工所接待的所有顾客花费的总时间来看,设一共有x个人,那么第一个修的对总时间的贡献是x*w1,第二个是(x-1)*w2-以此类推.所以把第i个修车工拆成n组 ...
随机推荐
- Meet Github
Source: http://www.liaoxuefeng.com/ Here only the local part. Install on windows download: https://g ...
- ASP.NET 单点登陆
第一种:同主域但不同子域之间实现单点登陆 Form验证其实是基于身份cookie的验证.客户登陆后,生成一个包含用户身份信息(包含一个ticket)的cookie,这个cookie的名字就是在web. ...
- usb驱动开发22之驱动生命线
我们总是很喜欢高潮,不是吗?那就好好对待她哦.我们来看一下linux中的高潮部分设备是怎么从Address进入Configured的. usb_set_configuration函数的代码就不贴了,可 ...
- css 内容超过容器宽度,checkbox等控件不会随着内容延伸
<div a> <div id='内容容器'> <div>很长的内容</div><input type='checkbox'/> </ ...
- Java7并发编程实战(一) 线程的管理
1:线程的创建 1:继承Thread类,并且覆盖run()方法 2:创建一个实现Runnable接口的类.使用带参数的Thread构造器来构造 2:example-->计算打印乘法表 首先 ...
- QT 智能提示设置
qt5.0的智能提示设置 qt默认的是Ctrl+空格 但这个是切换输入法,用着也不习惯 修改的地方是 工具->选项->环境 键盘选项把CompleteThis修改成自己习惯的快捷键
- c++ 头文件
可以将程序分为二部分: 头文件:包含结构声明和使用这些结构的函数的原型 源代码文件: 包含与结构有关的函数的代码 不要将函数的定义或变量的声明放在头文件里, 一般头文件可以包含以下内容 >函数原 ...
- 提高Visual Studio开发性能的几款插件
通过打开Visual Studio,单机TOOLS—Extensions and Updates-Online-Visual Studio Gallery(工具-扩展和更新-联网-Visual Stu ...
- Redis Sentinel:集群Failover解决方案(转载)
本文转载自:http://shift-alt-ctrl.iteye.com/blog/1884370 文中的配置例子,还有failover过程中触发的订阅事件具有很好的参考价值. Redis sent ...
- .Net相关
Lucene 全文搜索 http://lucenenet.apache.org/ Memcached 分布式缓存 http://memcached.org/ selenium UI自动化测试 http ...