• [bzoj4873]寿司餐厅


    来自FallDream的博客,未经允许,请勿转载,谢谢。


    Kiana最近喜欢到一家非常美味的寿司餐厅用餐。每天晚上,这家餐厅都会按顺序提供n种寿司,第i种寿司有一个代号ai和美味度di,i,不同种类的寿司有可能使用相同的代号。每种寿司的份数都是无限的,Kiana也可以无限次取寿司来吃,但每种寿司每次只能取一份,且每次取走的寿司必须是按餐厅提供寿司的顺序连续的一段,即Kiana可以一次取走第1,2种寿司各一份,也可以一次取走第2,3种寿司各一份,但不可以一次取走第1,3种寿司。由于餐厅提供的寿司种类繁多,而不同种类的寿司之间相互会有影响:三文鱼寿司和鱿鱼寿司一起吃或许会很棒,但和水果寿司一起吃就可能会肚子痛。因此,Kiana定义了一个综合美味度di,j(i<j),表示在一次取的寿司中,如果包含了餐厅提供的从第i份到第j份的所有寿司,吃掉这次取的所有寿司后将获得的额外美味度。由于取寿司需要花费一些时间,所以我们认为分两次取来的寿司之间相互不会影响。注意在吃一次取的寿司时,不止一个综合美味度会被累加,比如若Kiana一次取走了第1,2,3种寿司各一份,除了d1,3以外,d1,2,d2,3也会被累加进总美味度中。神奇的是,Kiana的美食评判标准是有记忆性的,无论是单种寿司的美味度,还是多种寿司组合起来的综合美味度,在计入Kiana的总美味度时都只会被累加一次。比如,若Kiana某一次取走了第1,2种寿司各一份,另一次取走了第2,3种寿司各一份,那么这两次取寿司的总美味度d1,1+d2,2+d3,3+d1,2+d2,3,其中d2,2只会计算一次。奇怪的是,这家寿司餐厅的收费标准很不同寻常。具体来说,如果Kiana一共吃过了c(c>0)种代号为x的寿司,则她需要为这些寿司付出mx^2+cx元钱,其中m是餐厅给出的一个常数。现在Kiana想知道,在这家餐厅吃寿司,自己能获得的总美味度(包括所有吃掉的单种寿司的美味度和所有被累加的综合美味度)减去花费的总钱数的最大值是多少。由于她不会算,所以希望由你告诉她。
    n<=100 ai<=1000
     
    貌似是叫最大权闭合子图
    也就是如果你选了[i,j],你就必须选[i,j-1]和[i+1,j]
    考虑最小割,先对于每一个编号建出一个点,从它向T连编号平方*m的边。
    对于区间[i,j]
    如果ij不等,先向[i,j-1][i+1,j]两个点连INF的边,然后如果点权正数就让答案加上它并且从S向它连点权的边,否则向T连点权的边。
    如果ij相等,它的点权减去ai ,并且向它的编号对应节点连INF的边;和S,T的建边方法相同
    然后最小割。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define S 0
    #define MN 11001
    #define INF (ll)1e18
    #define num(x,y) (x-1)*n+y
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') x=x*10+ch-'0', ch=getchar();
        return x*f;
    }
    
    ll ans=0;
    int head[MN+5],c[MN+5],d[MN+5],T,top,a[105],q[MN+5],cnt=1,n,m,s[105][105];
    struct edge{int to,next;ll w;}e[MN*100];
    
    inline void ins(int f,int t,ll w)
    {
        e[++cnt]=(edge){t,head[f],w};head[f]=cnt;
        e[++cnt]=(edge){f,head[t],0};head[t]=cnt;
    }
    
    bool bfs()
    {
        memset(d,0,sizeof(int)*(T+1));int i,j;
        for(d[q[top=i=1]=S]=1;i<=top;++i)
            for(int j=c[q[i]]=head[q[i]];j;j=e[j].next)
                if(e[j].w&&!d[e[j].to])
                    d[q[++top]=e[j].to]=d[q[i]]+1;
        return d[T];
    }
    
    ll dfs(int x,ll f)
    {
        if(x==T) return f;ll used=0;
        for(int&i=c[x];i;i=e[i].next)
            if(e[i].w&&d[e[i].to]==d[x]+1)
            {
                int w=dfs(e[i].to,min(f-used,e[i].w));
                used+=w;e[i].w-=w;e[i^1].w+=w;
                if(used==f) return f;
            }
        return d[x]=-1,used;
    }
    
    int main()
    {
        n=read();m=read();T=n*n+1001;
        for(int i=1;i<=1000;++i) ins(n*n+i,T,1LL*i*i*m);
        for(int i=1;i<=n;++i) a[i]=read();
        for(int i=1;i<=n;++i)
            for(int j=i;j<=n;++j)
            {
                s[i][j]=read();
                if(i!=j) ins(num(i,j),num(i+1,j),INF),
                    ins(num(i,j),num(i,j-1),INF);
                else s[i][j]-=a[i],ins(num(i,j),n*n+a[i],INF);
                if(s[i][j]>0) ans+=s[i][j],ins(S,num(i,j),s[i][j]);
                if(s[i][j]<0) ins(num(i,j),T,-s[i][j]);
            }
        while(bfs()) ans-=dfs(S,INF);
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    数据应用
    Python邮件脚本
    函数
    tab模块
    python登陆,注册小程序
    三元运算+lambda表达式
    计算机基础
    软件测试概要
    asyn_fifo
    perl 对ENV环境变量的使用
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4873.html
Copyright © 2020-2023  润新知