您的位置:首页 > 其它

Orz教主第6次模拟赛之教主的别墅

2017-06-30 20:24 246 查看

题目

https://jzoj.net/senior/#main/show/1795

小结

你绝对想不到这是一道贪心题!!

很恶心,想了很久。。。。

首先,我们看看这个数据:

10 4

0001000000

让你切4份对吧。我们只需要找o(n)扫一遍。

首先算前缀和,算出

—0001000000

S:1232345678

把“1”当做-1,把“0”当做1去算。

我们很显然可以发现,最终的答案是|Snm上取整对吧。

这一点清楚了,我们就记录l为上一个分开的地方。

于是当s[i]-s[l]<=ans 时

再看

__00|01000000

S:12|12123456

|s[n]−s[i]m(上取整)<=ans

那么我们就直接切,这样就保证了字典序最小。

至于最大,
4000
只需要反过来做一遍就好了。。。。。

(^__^)

打了我好久>>>>

var
n,m,i,ans,l,k,m1:longint;
s:ansistring;
sum,ans1:array[0..5000000]of longint;
begin
readln(n,m);
m1:=m;
readln(s);
for i:=1 to length(s) do
if s[i]='1' then sum[i]:=sum[i-1]-1
else sum[i]:=sum[i-1]+1;
if sum
=0 then
begin
l:=0;
for i:=1 to n do
if sum[i]=0 then inc(l);
if l>=m then ans:=0
else ans:=1;
end
else
begin
ans:=trunc(abs(sum
)/m);
if abs(sum
) mod m>0 then inc(ans);
end;
l:=0;
for i:=1 to n do
begin
if sum[i]-sum[l]<=ans then
begin
k:=trunc(abs(sum
-sum[i])/(m-1));
if abs(sum
-sum[i]) mod (m-1)>0 then inc(k);
if k<=ans then
begin
write(i-l,' ');
l:=i;
m:=m-1;
end;
end;
if m=1 then
begin
writeln(n-l);
break;
end;
end;
for i:=length(s) downto 1 do
if s[i]='1' then sum[i]:=sum[i+1]-1
else sum[i]:=sum[i+1]+1;
m:=m1;
if sum[1]=0 then
begin
l:=0;
for i:=1 to n do
if sum[i]=0 then inc(l);
if l>=m then ans:=0
else ans:=1;
end
else
begin
ans:=trunc(abs(sum[1])/m);
if abs(sum[1]) mod m>0 then inc(ans);
end;
l:=n+1;
for i:=n downto 1 do
begin
if sum[l]-sum[i]<=ans then
begin
k:=trunc(abs(sum[i]-sum[1])/(m-1));
if abs(sum[i]-sum[1]) mod (m-1)>0 then inc(k);
if k<=ans then
begin
inc(ans1[0]);
ans1[ans1[0]]:=l-i;
l:=i;
m:=m-1;
end;
end;
if m=1 then
begin
write(l-1,' ');
break;
end;
end;
for i:=ans1[0] downto 1 do
write(ans1[i],' ');
writeln;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  题解