3141: [Hnoi2013]旅行 - BZOJ
Description
Input
第一行为两个空格隔开的正整数n, m,表示旅行的城市数与旅行所花的月数。接下来n行,其中第 i行包含两个空格隔开的整数Ai和Bi,Ai表示他第i个去的城市编号。Bi为0或1;如果Bi=0则表示城市Ai没有小L想去的景点,如果Bi=1则表示城市Ai有小L想去的景点,
Ai两两不同且有1<=Ai<=N,即{Ai}为1,2....N的一个排列。
例如{2,1,3,4...N}
N<=500000,M<=200000
Output
t仅包括一行,包含m个空格隔开的正整数X1,X2...Xm,t仅包括一行,包含m个空格隔开的正整数X1,X2...Xm,为给小L安排的旅行计划对应的路线。为给小L安排的旅行计划对应的路线。
Sample Input
8 3
2 0
3 1
4 1
1 0
5 0
6 1
7 1
8 0
Sample Output
1 6 8
HINT
第1个月得到2点快乐值与2点疲劳值,第2个月得到1点快乐值与1点疲劳值,第3 个月得到1点快乐值与1点疲劳值。3个月中疲劳值与快乐值差的最大值为0,达到所有方 案最小值。
可行方案有:
1 6 8
3 6 8
3 1 8
其中1 6 8字典序最小。
感谢两位的题解http://www.cnblogs.com/lazycal/archive/2013/07/29/3221342.html和http://cxjyxx.me/?p=329
基本上就是他们说的了,本人愚笨,两天才刷掉它
我就随便讲一下 对每一个s[i]做一个单调队列 在单调队列里维护a[i]单调递增 当ans为0时 每次把可以作为解的点加入单调队列,把a[i]比他小的都删掉,然后取队头 当ans不为0时 如果n-m+1可以做现在的解,把n-m+1这个点加进单调队列,操作一样 为什么可以这样做,我认为是因为入队的顺序本来是按从近到远的顺序,而且都可以作为现在的解,如果a[i]比a[j]大,j在i后面,那肯定就把i删除了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 var 2 s,sum,sum2,c:array[0..500010]of longint; 3 first,tail:array[-500010..500010]of longint; 4 next,pre,num:array[0..1000010]of longint; 5 n,m,ans,tot,l:longint; 6 7 function get(l,m:longint):longint; 8 begin 9 if sum[l]=0 then 10 if sum2[l]>=m then exit(0) 11 else exit(1) 12 else 13 begin 14 get:=abs(sum[l])div m; 15 if abs(sum[l])mod m>0 then inc(get); 16 end; 17 end; 18 19 procedure insert(x:longint); 20 var 21 i:longint; 22 begin 23 if get(x+1,m-1)>ans then exit; 24 inc(tot); 25 num[tot]:=x; 26 if first[sum[x+1]]=0 then 27 begin 28 first[sum[x+1]]:=tot; 29 tail[sum[x+1]]:=tot; 30 exit; 31 end; 32 i:=tail[sum[x+1]]; 33 while (i<>0)and((c[num[i]]>c[x])or(num[i]<l)) do 34 begin 35 if pre[i]=0 then 36 begin 37 i:=0; 38 break; 39 end; 40 i:=pre[i]; 41 end; 42 if i=0 then 43 begin 44 first[sum[x+1]]:=tot; 45 tail[sum[x+1]]:=tot; 46 exit; 47 end; 48 pre[tot]:=i; 49 next[i]:=tot; 50 tail[sum[x+1]]:=tot; 51 end; 52 53 procedure work2; 54 var 55 i,k:longint; 56 begin 57 l:=1; 58 k:=1; 59 while m>1 do 60 begin 61 while sum2[k]>=m-1 do 62 begin 63 if sum[k+1]=0 then insert(k); 64 inc(k); 65 end; 66 while num[first[0]]<l do 67 first[0]:=next[first[0]]; 68 pre[first[0]]:=0; 69 write(c[num[first[0]]],' '); 70 l:=num[first[0]]+1; 71 dec(m); 72 end; 73 write(c[n]); 74 halt; 75 end; 76 77 procedure init; 78 var 79 i:longint; 80 begin 81 read(n,m); 82 for i:=1 to n do 83 begin 84 read(c[i],s[i]); 85 if s[i]=0 then s[i]:=-1; 86 end; 87 for i:=n downto 1 do 88 begin 89 sum[i]:=sum[i+1]+s[i]; 90 sum2[i]:=sum2[i+1]; 91 if sum[i]=0 then inc(sum2[i]); 92 end; 93 ans:=get(1,m); 94 if ans=0 then work2; 95 for i:=1 to n-m do 96 insert(i); 97 end; 98 99 procedure work; 100 var 101 i,j,min,sl,sr:longint; 102 begin 103 l:=1; 104 while m>1 do 105 begin 106 insert(n-m+1); 107 sl:=sum[l]-ans; 108 sr:=ans+sum[l]; 109 j:=5000000; 110 min:=5000000; 111 for i:=sl to sr do 112 begin 113 while (first[i]<>0)and((num[first[i]]<l)or(get(num[first[i]]+1,m-1)>ans)) do 114 first[i]:=next[first[i]]; 115 pre[first[i]]:=0; 116 if first[i]<>0 then 117 if c[num[first[i]]]<min then 118 begin 119 min:=c[num[first[i]]]; 120 j:=num[first[i]]; 121 end; 122 end; 123 write(min,' '); 124 l:=j+1; 125 dec(m); 126 end; 127 write(c[n]); 128 end; 129 130 begin 131 init; 132 work; 133 end.