題目鏈接: https://codeforces.com/contest/1146/problem/G
題意:
你現在要給 個位置制定高度 ,每個位置 的高度可以帶來 的收益,但是有 條限制,每個限制 的信息爲 表示從位置 位置 當中如果有任意一個位置的高度超過了 那麼就要罰款 ,現在問你最大的總收益爲多少。
做法:
因爲 的大小均不超過 ,所以還是很明顯能感受到是最大流的。套路無非就是 原最大收益-最小代價,代價在 只到達這個高度的損失 和 到達這個高度所要接受的罰款 裏面選出更小的,那麼這個更小的值的就靠 最大流=最小割 來維護了。
我想了挺久的,其實一開始方向蠻對的,每個位置每個高度一個點,每個條件一個點,但是不知道爲什麼後來就偏了,想用區間來表示(腦子瓦特了還順着這個錯誤的方向想了很久)。
略過略過,其實沿着一開始的思路的話還是很順的想的。把點按照高度拆開,高度 向高度 連一條只達到高度 時要損失的代價。然後將限制條件 中每一個合法的位置 的高度爲 的點向限制條件連一條邊, 本身向匯點連一條代價這麼多的邊即可。
畫了個醜陋的圖,第一個樣例幫助理解。
代碼
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
#define pb push_back
#define lson rt<<1
#define rson rt<<1|1
#define mid (l+r)/2
using namespace std;
const int maxn=2800;
const int maxm=30005;
const int inf = 1<<30;
typedef long long ll;
int nex[maxm],to[maxm],cap[maxm],from[maxm];
int n,m,h,cnt,head[maxn],d[maxn],sp,tp;//原點,匯點
//理論複雜度n2*m
void add(int u,int v,int c){
//printf("from = %d to = %d cap = %d\n",u,v,c);
from[cnt]=u,to[cnt]=v,cap[cnt]=c,nex[cnt]=head[u],head[u]=cnt++;
from[cnt]=v,to[cnt]=u,cap[cnt]=0,nex[cnt]=head[v],head[v]=cnt++;
}
int bfs(){
queue <int> q;
memset(d,-1,sizeof(d));
d[sp]=0;
q.push(sp);
while(!q.empty()){
int cur=q.front();
q.pop();
for(int i=head[cur];i!=-1;i=nex[i]){
int u=to[i];
if(d[u]==-1 && cap[i]>0){
d[u]=d[cur]+1;
q.push(u);
}
}
}
return d[tp] != -1;
}
int dfs(int a,int b){
int r=0;
if(a==tp)return b;
for(int i=head[a];i!=-1 && r<b;i=nex[i])
{
int u=to[i];
if(cap[i]>0 && d[u]==d[a]+1)
{
int x=min(cap[i],b-r);
x=dfs(u,x);
r+=x;
cap[i]-=x;
cap[i^1]+=x;
}
}
if(!r)d[a]=-2;
return r;
}
int dinic(int sp,int tp){
int total=0,t;
while(bfs()){
while(t=dfs(sp,inf))
total+=t;
}
return total;
}
int gain(int id,int hei){
return (id-1)*(h+1)+hei+1;
}
int sub(int x){
return h*h-x*x;
}
int main(){
cnt=0;
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&h,&m);
int ans=n*h*h,np=(h+1)*n;
sp=0,tp=np+m+1;
rep(i,1,n){
add(sp,gain(i,0),inf);
rep(j,1,h){
add(gain(i,j-1),gain(i,j),sub(j-1));
}
}
rep(i,1,m){
int l,r,x,c; scanf("%d%d%d%d",&l,&r,&x,&c);
if(x==h) continue;
rep(j,l,r){
add(gain(j,x+1),np+i,inf);
}
add(np+i,tp,c);
}
printf("%d\n",ans-dinic(sp,tp));
return 0;
}