P3749 [六省联考2017]寿司餐厅

题意

首先因为每个值只会被算一次且值的个数为\(n^2\)级别的,因此我们可以对每个\(d_{i,j}\)开一个点,之后就可以用最大权闭合子图做。

考虑题目的限制:

1.选择一个区间\([l,r]\)会将\(\sum\limits_{i=l}^{r}\sum\limits_{j=i+1}^rd_{i,j}\)选上:
我们显然不能全部连上,这是\(n^4\)级别的,我们可以只从\(d_{i,j}\)向\(d_{i+1,j}\)和\(d_{i,j-1}\)连边。

2.如果吃过\(c\)种代号为\(x\)的寿司,会付出\(m*x^2+c*x\)的代价:
拆成两部分:
<1>选了\(c\)种代号为\(x\)的寿司会付出\(c*x\)的代价,即选了\(d_{i,i}\)就必定要付出\(a_i\)的代价。
<2>如果选了代号为\(x\)的寿司,就会付出\(m*x^2\)的代价:
我们对每个\(a_i\)也开一个点,点权为\(-a_i^2\)。

于是总结下连边是这样的:

对于\(d_{i,j}\):

如果\(i=j\):
从\(d_{i,i}\)向\(a_i\)连一条容量为\(inf\)的边,表示选了第\(i\)个就选了第\(a_i\)种。从\(d_{i,j}\)向汇点连一条容量为\(a_i\)的边,表示选了\(i\)号寿司需要付出\(a_i\)的代价。
反之:
从\(d_{i,j}\)向\(d_{i+1,j}\)和\(d_{i,j-1}\)连容量为\(inf\)的边。
最后根据点权正负向源点和汇点连边。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
const int inf=1e9;
int n,m,num,cnt=1,S,T,tot,ans;
int a[maxn],head[maxn*maxn+maxn],cur[maxn*maxn+maxn],dep[maxn*maxn+maxn];
int val[maxn][maxn],id[maxn][maxn];
struct edge{int to,nxt,flow;}e[(maxn*maxn+maxn)<<2];
inline void add(int u,int v,int w)
{
    e[++cnt].nxt=head[u];
    head[u]=cnt;
    e[cnt].to=v;
    e[cnt].flow=w;
}
inline bool bfs()
{
    memset(dep,0,sizeof(dep));
    for(int i=S;i<=T;i++)cur[i]=head[i];
    queue<int>q;
    q.push(S);dep[S]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(dep[y]||e[i].flow<=0)continue;
            dep[y]=dep[x]+1;q.push(y);
        }
    }
    return dep[T]>0;
}
int dfs(int x,int goal,int lim)
{
    if(x==goal||lim<=0)return lim;
    int res=lim;
    for(int i=cur[x];i;i=e[i].nxt)
    {
        cur[x]=i;
        int y=e[i].to;
        if(dep[y]!=dep[x]+1||e[i].flow<=0)continue;
        int tmp=dfs(y,goal,min(res,e[i].flow));
        if(tmp<=0)dep[y]=0;
        res-=tmp;
        e[i].flow-=tmp,e[i^1].flow+=tmp;
        if(res<=0)break;
    }
    return lim-res;
}
inline int Dinic()
{
    int res=0;
    while(bfs())res+=dfs(S,T,inf);
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),num=max(num,a[i]);
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
            scanf("%d",&val[i][j]),id[i][j]=++tot;
    S=0,T=tot+num+1;
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
        {
            int w=val[i][j];
            if(i==j)
            {
                if(m)add(id[i][j],tot+a[i],inf),add(tot+a[i],id[i][j],0);
                w-=a[i];
            }
            else
            {
                add(id[i][j],id[i+1][j],inf),add(id[i+1][j],id[i][j],0);
                add(id[i][j],id[i][j-1],inf),add(id[i][j-1],id[i][j],0);
            }
            if(w>=0)ans+=w,add(S,id[i][j],w),add(id[i][j],S,0);
            else add(id[i][j],T,-w),add(T,id[i][j],0);
        }
    if(m)
        for(int i=1;i<=num;i++)
            add(tot+i,T,i*i),add(T,tot,0);
    printf("%d",ans-Dinic());
    return 0;
}

原文地址:https://www.cnblogs.com/nofind/p/12088404.html

时间: 2024-07-29 17:56:30

P3749 [六省联考2017]寿司餐厅的相关文章

洛谷P3749 [六省联考2017]寿司餐厅

传送门 题解 这几道都是上周llj讲的题,题解也写得十分好了,所以直接贴了几个链接和代码. //Achen #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<vector> #include<queue> #include<cmath> #include<

bzoj千题计划265:bzoj4873: [六省联考2017]寿司餐厅

http://www.lydsy.com/JudgeOnline/problem.php?id=4873 选a必选b,a依赖于b 最大权闭合子图模型 构图: 1.源点 向 正美味度区间 连 流量为 美味度 的边 2.负美味度区间 向 汇点 连 流量为 美味度的绝对值 的边 3.区间[i,j] 向 区间[i+1,j].区间[i,j-1] 连 流量为 inf 的边 4.区间[i,i] 向 寿司i 连 流量为 inf 的边 5.寿司i 向 汇点 连 流量为 寿司代号 的边 6.寿司i 向 它的代号 连

[六省联考2017]寿司餐厅(最小割)

题意 题目 思路 由得到的权值不重复可以看出这是一道最大权闭合子图问题 (反正我是没看出来),即最小割 可以看出,如果得到了权值\(d_{l,r}\),可以且必须得到权值\(d_{x,y},(l\leq x \leq y\leq r)\),必须要花费\([l,r]\)这一区间的代价,于是可以得到建图方法 将一个区间看做一个点 \(d_{l,r}>0\),\(ans\) \(+=d_{l,r}\),\(S\)向它连边,边权为\(d_{l,r}\),割掉这条边表示不选择这个值,产生\(d_{l,r}

[六省联考2017]寿司餐厅

题链 这道题长着网络流的数据范围. 最大权闭合子图问题 跑最小割 #include<bits/stdc++.h> #define eho(x) for(int& i=hed[x];~i;i=net[i]) #define Eho(x) for(int i=head[x];~i;i=net[i]) #define N 52607 #define M 3500007 #define NN 1007 #define sight(c) (c<='9'&&c>='0'

P3746 [六省联考2017]组合数问题

P3746 [六省联考2017]组合数问题 \(dp_{i,j}\)表示前\(i\)个物品,取的物品模\(k\)等于\(r\),则\(dp_{i,j}=dp_{i-1,(j-1+k)%k}+dp_{i-1,j}\) \(dp_{i,0},dp_{i,1},dp_{i,2}.....dp_{i,k-1}\) \(\Longrightarrow\) \(dp_{i+1,0},dp_{i+1,1},dp_{i+1,2}.....dp_{i+1,k-1}\) 仔细想想,你能构造出矩阵的 #include

[luogu] P3745 [六省联考2017]期末考试 (贪心)

P3745 [六省联考2017]期末考试 题目描述 有 \(n\) 位同学,每位同学都参加了全部的 \(m\) 门课程的期末考试,都在焦急的等待成绩的公布. 第 \(i\) 位同学希望在第 \(t_i\)? 天或之前得知所有课程的成绩.如果在第 \(t_i\) 天,有至少一门课程的成绩没有公布,他就会等待最后公布成绩的课程公布成绩,每等待一天就会产生 \(C\) 不愉快度. 对于第 \(i\) 门课程,按照原本的计划,会在第 \(b_i\)? 天公布成绩. 有如下两种操作可以调整公布成绩的时间:

bzoj千题计划266:bzoj4872: [六省联考2017]分手是祝愿

http://www.lydsy.com/JudgeOnline/problem.php?id=4872 一种最优解是 从大到小灯有亮的就灭掉 最优解是唯一的,且关灯的顺序没有影响 最优解 对每个开关至多操作1次,(连带着的灯的亮灭改变不算) 设最优解 需要操作cnt次,那么就有cnt盏灯是正确的选择 设 f[i] 表示 有i种正确的选择  变为 有i-1种正确的选择 的 期望次数 那么在n盏灯中,有i盏灯操作1次 就可以 减少一次正确选择 有n-i盏灯是错误的选择,选了它还要把它还原,还原它也

[BZOJ4869][六省联考2017]相逢是问候(线段树+扩展欧拉定理)

4869: [Shoi2017]相逢是问候 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1313  Solved: 471[Submit][Status][Discuss] Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每

六省联考2017

期末考试 sol 因为时间范围很小,所以可以利用单调性求出对于每一个时间$t$,当最晚的成绩公布时间为$t$时学生产生的不满意度总和$f_t$和让所有课程的公布时间不大于$t$的前提下课程产生的最小不满意度$g_t$.复杂度$O(nlogn)$,瓶颈是排序. 但是上面那个做法太不优雅了.我们可以发现$g_t$和$f_t$差分之后的数组都是单调不减,也就是$f_t+g_t$差分之后单调不减,也就意味着$f_t+g_t$这个数列是单谷数列.我们在时间范围上三分数列极小值即可. 然后因为三分太慢获得了