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

题目

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
那么我们就直接切,这样就保证了字典序最小。
至于最大,只需要反过来做一遍就好了。。。。。
(^__^)
打了我好久>>>>

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[n]=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[n])/m);
                if abs(sum[n]) 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[n]-sum[i])/(m-1));
                        if abs(sum[n]-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.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值