BZOJ3308九月的咖啡店

3308: 九月的咖啡店
Time Limit: 30 Sec Memory Limit: 128 MB
Submit: 140 Solved: 49
Description
深绘里在九份开了一家咖啡让,如何调配咖啡民了她每天的头等大事
我们假设她有N种原料,第i种原料编号为i,调配一杯咖啡则需要在这
里若干种兑在一起。不过有些原料不能同时在一杯中,如果两个编号
为i,j的原料,当且仅当i与j互质时,才能兑在同一杯中。
现在想知道,如果用这N种原料来调同一杯咖啡,使用的原料编号之和
最大可为多少。
Input
一个数字N
Output
如题
Sample Input
10
Sample Output
30
HINT
1<=N<=200000
直观感受是,所有质因数分别单独存在于一个数中
但是还要考虑到,俩个质因数一起存在于一个数中可以更优
如3,5,n=20
9+5<3*5
听说,至多俩个质因数存在于一个数中0.0
且一个大于根号n,一个小于根号n
于是就能费用流最大费用匹配了(不断增广至费用<0)
一个优化是,先假设所有质因数单独存在,把这部分收益加入答案
若a,b能配对
a,b连边 权值Vab−Va−VbVab−Va−Vb
这样费用流就跑的飞起了
WA了8次。。
附上本蒟蒻的代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
#define inf 1000000000
#define MAXN 200001
int ans,n,tot,T,cnt=1,dis[MAXN],h[MAXN],prime[MAXN],q[MAXN],head,tail;
bool mark[MAXN],vis[MAXN];
vector<int>q1,q2;
struct kx
{
    int to,next,v,c;
}edge[MAXN*10];

int read()
{
    int w=0,c=1; char ch=getchar();
    while (ch<'0' || ch>'9')
      {
        if (ch=='-') c=-1;
        ch=getchar();
      }
    while (ch>='0' && ch<='9')
      w=w*10+ch-'0',ch=getchar();
    return w*c;
}

void add(int u,int v,int w,int cost)
{
    cnt++,edge[cnt]=(kx){v,h[u],w,cost};h[u]=cnt;
    cnt++,edge[cnt]=(kx){u,h[v],0,-cost};h[v]=cnt;
}

bool spfa()
{
    int i,now;
    for (i=0;i<=T;i++) dis[i]=-inf;
    head=0,tail=1,q[0]=T,dis[T]=0;
    while (head!=tail)
      {
        now=q[head],head++;
        if (head==200000) head=0;
        vis[now]=0;
        for (i=h[now];i;i=edge[i].next)
          if (edge[i^1].v && dis[now]-edge[i].c>dis[edge[i].to])
            {
              dis[edge[i].to]=dis[now]-edge[i].c;
              if (!vis[edge[i].to])
                {
                  q[tail++]=edge[i].to;
                  if (tail==200000) tail=0;
                  vis[edge[i].to]=true;
                }
            }
      }
    return dis[0]>0;
}

int dfs(int x,int f)
{
    mark[x]=true;
    if (x==T) return f;
    int w,used=0,i;
    for (i=h[x];i;i=edge[i].next)
      if (edge[i].v && dis[x]-edge[i].c==dis[edge[i].to] && !mark[edge[i].to])
        {
            w=dfs(edge[i].to,min(edge[i].v,f-used)),edge[i].v-=w,edge[i^1].v+=w;
            ans+=edge[i].c*w,used+=w;
            if (used==f) return f;
        }
    return used;
}

int v(int n,int x)
{
    long long t=x;
    while (x*t<=n) t*=x;
    return t;
}

void build()
{
    int i,a,b,tmp,j,t;
    for (i=1;i<=tot;i++)
      {
        t=prime[i];
        if (t*2>n) 
          {
            ans+=t;
            continue;
          }
        if ((long long)t*t<=n)
          {
            add(0,i,1,0);
            ans+=v(n,t);
            q1.push_back(i);
          }
        else
          {
            add(i,T,1,0);
            ans+=t;
            q2.push_back(i);
          }
      }
    for (i=0;i<q1.size();i++)
      for (j=0;j<q2.size();j++)
        {
            a=prime[q1[i]],b=prime[q2[j]];
            if (a*b<=n)
              {
                tmp=v(n/b,a)*b;
                if (tmp>v(n,a)+b)
                  add(q1[i],q2[j],1,tmp-(v(n,a)+b));
              }
            else break;
        }
}

int main()
{
    int i,j;
    n=read();
    for (i=2;i<=n;i++)
      {
        if (!mark[i]) prime[++tot]=i;
        for (j=1;prime[j]*i<=n && j<=tot;j++)
          {
            mark[prime[j]*i]=true;
            if (i%prime[j]==0) break;
          }
      }
    T=n+1;
    build();
    while (spfa())
      {
        for (i=0;i<=T;i++) mark[i]=false;
        mark[T]=true;
        while (mark[T])
          mark[T]=false,dfs(0,inf);
      }
    printf("%d",ans+1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值