JZOJ 4879 【NOIP2016提高A组集训第11场11.9】少女觉

本文讨论了一个特定的字符串处理问题:如何将一个仅包含两种字符的序列分割成尽可能多的子序列,使得每个子序列中两种字符的比例保持一致。文章详细阐述了解决方案,并通过Pascal代码实现了算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

少女觉

题目大意

给出一个长度为N的只含AB两种字母的序列,现在要将序列分成若干段,若每一段中字母AB的个数的比值都相等,则称这种分发是一种合法的分发。问题是求能将这段序列分成最多段的分发。

数据范围

N105

题解

设每一段中字母AB的个数的比值=k,则可以证明,k=等于整个序列中AB的个数的比值。
在证明一个结论,假若前i个已经被分了,现在有两个位置可选为分割点,分别为l,j,可以证明,显然此时应两个位置都选为分割点,在这种情况下可以满足题目的条件。
那我们只需要顺着O(n)找一次即可。

Code(Pascal)

var
    sz:array[0..120000,1..2] of longint;
    t,n,m,j,k,i,o,ans,u,js:longint;
    ff,kk:array[0..1] of int64;
    ch,cc:char;
function gcd(a,b:int64):int64;
    var
        t:int64;
    begin
        repeat
            t:=a mod b;
            a:=b;
            b:=t;
        until t=0;
        exit(a);
    end;
begin
    readln(t);
    for k:=1 to t do
    begin
        readln(n);
        ch:='0';
        o:=0;
        for i:=1 to n do
        begin
            read(m);
            read(cc); readln(cc);
            if cc<>ch then
            begin
                inc(o);
                if cc='W' then
                sz[o,1]:=0 else sz[o,1]:=1;
                sz[o,2]:=m;
            end
            else sz[o,2]:=sz[o,2]+m;
            ch:=cc;
        end;
        ff[0]:=0;
        ff[1]:=0;
        for i:=1 to o do
        inc(ff[sz[i,1]],sz[i,2]);
        if ff[0]*ff[1]=0 then writeln(ff[0]+ff[1])
        else
        begin
        js:=gcd(ff[0],ff[1]);
        ff[0]:=ff[0] div js;
        ff[1]:=ff[1] div js;
        kk[0]:=0;
        kk[1]:=0;
        ans:=0;
        for i:=1 to o do
        begin
            u:=sz[i,1];
            inc(kk[u],sz[i,2]);
            if kk[1-u]<>0 then
            if kk[1-u] mod ff[1-u]=0 then
            if (kk[1-u] div ff[1-u])*ff[u]<=kk[u] then
            if (kk[1-u] div ff[1-u])*ff[u]>=kk[u]-sz[i,2] then
            begin
                inc(ans);
                kk[u]:=kk[u]-(kk[1-u] div ff[1-u])*ff[u];
                kk[1-u]:=0;
            end;
        end;
        writeln(ans);
        end;
    end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值