Loading

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

链接:https://www.luogu.com.cn/problem/P3749

题解:由于\(mx^2\)让我们无法设\(dp\)状态,那么考虑网络流。

将每一个区间看作点,可以发现这是一个最大权闭合子图的模型。

考虑\(mx^2\)的限制,我们可以将点向代号连边,然后跑\(dinic\)即可。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int a[101],f[101][101],d[101][101],n,m;
int read()
{
  char c=0;
  int sum=0;
  while (c<'0'||c>'9')
      c=getchar();
  while ('0'<=c&&c<='9')
    {
      sum=sum*10+c-'0';
      c=getchar();
    }
  return sum;
}
struct node
{
  int v,nxt,data;
};
node edge[400001];
int maxflow,len,head[100001],cur[100001],depth[100001],s,t,N;
void add(int x,int y,int z)
{
  edge[++len].v=y,edge[len].data=z,edge[len].nxt=head[x],head[x]=len;
  edge[++len].v=x,edge[len].data=0,edge[len].nxt=head[y],head[y]=len;
  return;
}
bool bfs()
{
  int top;
  queue<int>q;
  for (int i=s;i<=t;++i)
    depth[i]=0;
  q.push(s);
  depth[s]=1;
  while (!q.empty())
    {
      top=q.front();
      q.pop();
      for (int i=head[top];i>0;i=edge[i].nxt)
	if (edge[i].data&&!depth[edge[i].v])
	  {
	    depth[edge[i].v]=depth[top]+1;
	    if (edge[i].v==t)
	      return 1;
	    q.push(edge[i].v);
	  }
    }
  return 0;
}
int dinic(int x,int flow)
{
  if (x==t)
    return flow;
  int k,res;
  for (int &i=cur[x];i>0;i=edge[i].nxt)
    if (edge[i].data&&depth[edge[i].v]==depth[x]+1)
      {
	k=dinic(edge[i].v,min(flow,edge[i].data));
	if (k==0)
	  depth[edge[i].v]=0;
	else
	  {
	    edge[i].data-=k;
	    edge[i^1].data+=k;
	    return k;
	  }
      }
  return 0;
}
int main()
{
  len=1;
  n=read(),m=read();
  for (int i=1;i<=n;++i)
    a[i]=read();
  for (int i=1;i<=n;++i)
    for (int j=i;j<=n;++j)
      scanf("%d",&d[i][j]);
  for (int i=1;i<=n;++i)
    d[i][i]-=a[i];
  for (int i=1;i<=n;++i)
    for (int j=i;j<=n;++j)
      f[i][j]=++N;
  s=0,t=N+1000+1;
  for (int i=1;i<=n;++i)
    for (int j=i+1;j<=n;++j)
      {
	add(f[i][j],f[i][j-1],1e9);
	add(f[i][j],f[i+1][j],1e9);
      }
  for (int i=1;i<=n;++i)
      add(f[i][i],N+a[i],1e9);
  for (int i=1;i<=n;++i)
    for (int j=i;j<=n;++j)
      {
	if (d[i][j]<0)
	  add(f[i][j],t,-d[i][j]);
	if (d[i][j]>0)
	  {
	    add(s,f[i][j],d[i][j]);
	    maxflow+=d[i][j];
	  }
      }
  for (int i=1;i<=1000;++i)
      add(N+i,t,i*i*m);
  int flow;
  while (bfs())
    {
      for (int i=s;i<=t;++i)
	cur[i]=head[i];
      while (flow=dinic(s,1e9))
	  maxflow-=flow;
    }
  printf("%d\n",maxflow);
  return 0;
}
posted @ 2022-12-14 21:59  zhouhuanyi  阅读(37)  评论(0)    收藏  举报