【XSY2689】王子 - 網路流
復活!qwq
題目來源:2018冬令營模擬測試賽(九)
題意:
【背景描述】
不是所有王子都會遇見自己的中關村,主公,公主。
從前有個王子姓王,王王子遇到了一位美麗的公主,她的名字當然是公公主啦。
王王子對公公主一見鍾情,他想方設法地去討好公公主, 他準備了N個節目依次表演給公主看,每個節目他可以倒立表演,或者正常表演。王王子非常聰明,所以他總是能預估出每個節目的每種表演形式能刷多少好感度,我們記第i個節目倒立表演能增加Ai的好感度,正常表演能增加Bi的好感度。
這個公公主也不是一個省油的燈,他(沒打錯)看節目的時候既不喜歡太循規蹈矩,也不喜歡太標新立異。準確的說,他看的王子表演的任意連續K個節目裡面,至少有P個倒立表演的節目,Q個正常表演的節目。
王王子想知道,在滿足公公主的特殊癖好的前提下,他最多能刷多少的好感度。
【輸入資料】
第一行四個整數N,K,P,Q。
接下來N行每行兩個整數表示Ai和Bi。
【輸出資料】
一行一個正整數表示答案。
【資料規模】
對於 20% 的資料,N < 16。
對於另外 30% 的資料, K < 10。
對於另外 30% 的資料, Ai, Bi < 4
對於 100% 的資料, 0 < N < 200, 0 < Ai, Bi < 10000000, 0 ≤ P + Q ≤ K ≤ N。
題解:
這種鬼畜題面和資料範圍肯定就是網路流啦~
題目中一共有$N-K+1$個限制區間,顯然一個節目倒立表演的話所有包含它的區間倒立表演的機會都少了一個;
那麼可以把每個區間看成一個點,一個流量就表示一次倒立表演的機會,那麼一個節目就會對應從最前的一個包含它的區間到最前的一個不包含它的區間的一條邊,表示如果倒立表演,這些區間的機會都會減少一個(流量流掉了);
限制倒立的節目最多有多少個就相當於限制總流量,直接限制每個點到下一個點的邊的流量即可;
加上最優的限制條件可以考慮先全選$A_i$,然後把費用設成$A_i-B_i$;
然後就是費用流隨便跑了。
程式碼:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 using namespace std;
10 typedef long long ll;
11 struct edge{
12 int v,w,z,next;
13 }a[100001];
14 int n,k,p,q,ans=0,N,vs,vt,tot=1,head[50001],sp[50001],fr[50001],s1[201],s2[201];
15 bool isin[50001];
16 void add(int u,int v,int w,int z){
17 a[++tot].v=v;
18 a[tot].w=w;
19 a[tot].z=z;
20 a[tot].next=head[u];
21 head[u]=tot;
22 a[++tot].v=u;
23 a[tot].w=0;
24 a[tot].z=-z;
25 a[tot].next=head[v];
26 head[v]=tot;
27 }
28 bool spfa(){
29 int flw,mi=inf;
30 queue<int>q;
31 memset(isin,0,sizeof(isin));
32 for(int i=0;i<=N;i++)sp[i]=-inf;
33 q.push(vs);
34 isin[vs]=true;
35 sp[vs]=0;
36 while(!q.empty()){
37 int u=q.front();
38 q.pop();
39 isin[u]=false;
40 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
41 int v=a[tmp].v;
42 if(sp[v]<sp[u]+a[tmp].z&&a[tmp].w){
43 fr[v]=tmp;
44 sp[v]=sp[u]+a[tmp].z;
45 if(!isin[v]){
46 q.push(v);
47 isin[v]=true;
48 }
49 }
50 }
51 }
52 if(sp[vt]==-inf)return false;
53 for(int i=vt;i!=vs;i=a[fr[i]^1].v){
54 mi=min(mi,a[fr[i]].w);
55 }
56 for(int i=vt;i!=vs;i=a[fr[i]^1].v){
57 ans+=mi*a[fr[i]].z;
58 a[fr[i]].w-=mi;
59 a[fr[i]^1].w+=mi;
60 }
61 return true;
62 }
63 int main(){
64 memset(head,-1,sizeof(head));
65 scanf("%d%d%d%d",&n,&k,&p,&q);
66 for(int i=1;i<=n;i++){
67 scanf("%d%d",&s1[i],&s2[i]);
68 ans+=s2[i];
69 }
70 vs=0;
71 vt=n+1;
72 N=n+2;
73 add(vs,N,k-q,0);
74 for(int i=1;i<=k;i++){
75 add(N,i,1,0);
76 }
77 for(int i=1;i<=n;i++){
78 add(i,i+1,k-q-p,0);
79 if(i+k<=n)add(i,i+k,1,s1[i]-s2[i]);
80 else add(i,vt,1,s1[i]-s2[i]);
81 }
82 while(spfa());
83 printf("%d",ans);
84 return 0;
85 }