P8437 题解

· · 题解

打回去了一次QAQ 有些地方忘记加空格了

打月赛,只做出这一题......

个人认为这一题与NOI Online 2021的T1 切蛋糕有异曲同工之妙,都不涉及什么算法,得大量分类讨论,极其容易忽略情况(对某些赛制很不友好)。

我的想法:让长度为 m 的“神之子串”放在最前面,并保证后来不会再出现长度超过 m 的“神之子串”。

怎么实现呢?如果 n 等于 m ,那就好办了,让两个字母交替出现即可。但如果 n 小于 m,就要考虑后面的字符串该怎么安排了。

观察下面的字符串:

当m=6:
lrlrlrrrlrlrlrrrlrlrlrrrlrlrlr

不难发现,连续出现三次(及以上)同一个字符可以分隔不同的“神之子串”,所以我们可以让 lr 交替出现,在长度达到 m 时再输出两个与当前"神之子串"末尾相同字符断开当前的“神之子串”,再继续让 lr 交替出现,于是我们可以写下如下代码:

for(int i=1;i<=n;i++){
    if(l<m){  //在交替出现l与r
        if(l%2)cout<<'l';
        else cout<<'r';
    }else{
        if(i==n){
            if(l%2)cout<<'l';
            else cout<<'r';
            break;
        }if(i==n-1){
            if(l%2)cout<<"lr";
            else cout<<"rl";
            break;
        }
        if(l%2)cout<<"lrr";
        else cout<<"rll";
        l=0;i+=2;
    }l++;
}

但这种方法有个问题:首先,要断开当前的连续子串,必须要让 k≥3 ;其次,这种方法在 m=2 时行不通(你可以自己试一下)。所以我们就要讨论各种 k 小于 3 的情况了

1.如果 k=2 :

老样子,让 lr 交替出现,但要断开数组就有问题了,由于只能让相同的字符连续出现两次,所以看看下面的字符串


设m=4:
lrlr

lrlrllr

也不难发现,在一个不能再往后扩展的"神之子串"后面,顶多再坚持三个字符,再往后"神之子串"长度就要超过 m 了。

那后面怎么办呢?

你读了读题,看见了这样一句话:数据保证可以找出神 TU 喜欢的字符串

所以就直接用 llr 结尾就行啦(注意字符串长度别超过 n

代码如下:

for(int i=1;i<m/2;i++){//先lr互相出现
    cout<<"lr";
}n-=2*(m/2-1);
for(int i=1;i<=n;i++){//再用llr结尾
    if(i%3)cout<<'l';
    else cout<<'r';
}return 0;

2.如果 k=1

那就只能 lr 一直交替出现下去,根据那句"数据保证可以找出神 TU 喜欢的字符串"就知道,交替出现到结尾就是答案啦。再看看我们一开始写的没有任何特殊条件的代码,行吧,这种情况不需要写特殊代码,直接跑一开始写的代码就能得出答案

3.如果 m=2

$k=1$ 刚刚我们讨论完,所以只要考虑 $k=2$ 了。 解决方法也是简单明了:直接打表 在 $k=1$ 且 $m=2$ 的情况下,字符串不会太长,最长为5,以下是一种排法: ``` llrll ``` 这个字符串可以应付 $3≤n≤5$,输出前 $n$ 个字符即可,再特判 $n=2$,如果是这种情况,输出 “lr” 就完事啦~ 代码如下: ``` bool five_two[5]={1,1,0,1,1}; if(m==2&&k==2){ if(n==5||n==4||n==3){ for(int i=0;i<n;i++){ if(five_two[i])cout<<'l'; else cout<<'r'; } }else if(n==2){ cout<<"lr"; } return 0; } ``` 所有情况讨论完了,下面是完整 AC 代码: ``` #include<bits/stdc++.h> using namespace std; int n,m,k,l=1; bool five_two[5]={1,1,0,1,1}; int main() { cin>>n>>m>>k; if(m==2&&k<3){ if(n==5||n==4||n==3){ for(int i=0;i<n;i++){ if(five_two[i])cout<<'l'; else cout<<'r'; } }else if(n==2){ cout<<"lr"; } return 0; }if(k==2){ for(int i=1;i<m/2;i++){ cout<<"lr"; }n-=2*(m/2-1); for(int i=1;i<=n;i++){ if(i%3)cout<<'l'; else cout<<'r'; }return 0; }for(int i=1;i<=n;i++){ if(l<m){ if(l%2)cout<<'l'; else cout<<'r'; }else{ if(i==n){ if(l%2)cout<<'l'; else cout<<'r'; break; }if(i==n-1){ if(l%2)cout<<"lr"; else cout<<"rl"; break; } if(l%2)cout<<"lrr"; else cout<<"rll"; l=0;i+=2; }l++; } return 0; } ``` 有些地方表述可能不当,如果有需要修改的地方请指正,谢谢