<h2>题目描述</h2>

令 $s_i$ 表示第 $i$ 个字符串,我们有递推式 $s_i = s_{i-2}+s_{i-1}$(其中+ 是将两个字符串拼接起来的符号)
现在需要你构造出长度为 $n$ 的 $s_1$ 和长度为 $m$ 的 $s_2$ ,满足 $s_k$ 中串 AC 作为子串出现了 $x$ 次。
$3 \leq k \leq 50,0 \leq x \leq 10^9,1 \leq n,m \leq 100$

<h2>题解</h2>

这个题还挺有意思的... dp 可以记录一些状态,不只是记录一个孤零零的值。
首先我们发现最后只需要关心的是 $AB$ 的数量,可能就会想到令 $f_{i}$ 表示 $s_i$ 的 AC 的数量,转移直接 $f_i = f_{i-1}+f_{i-2}$。但这显然不太对,因为中间可能还会拼接起来。
这时候我们的 dp 数组就要多记录点东西了:考虑类似于线段树维护最大字段和那样,$f_i$ 记录一个三元组 $(a,b,c)$ 表示左边的字母是 $a$,AC 的数量为 $b$ ,右边的字母为 $c$ 的数量。拼接的时候只需要看左边字符串的最右端和右边字符串的最左端 更新一下 $b$ 就好了。
然后我们发现 $n,m,k$ 都很小,一个自然的想法是枚举。但是一开始可能会发现枚举要确定头尾是什么字母,还要确定后面会不会和头尾产生新的 AC... 太麻烦了。但是仔细一想可以发现我们其实只需要确定 AC 的个数和头是不是 C,结尾是不是 A 就可以了。这些情况是不会对里面产生影响的,并且产生影响的情况和左右都填其他字母的情况等价。(要不是看了题解发现这种枚举方法我估计就要写大大大分类讨论了 qaq)
然后直接模拟输出就可以了.

<h2>代码</h2>

/*
 * sto Qingyu orz
 * 感谢真神sqy无私的教诲。膜时队者处处阿克,只因大师sqy在他背后。不膜大师者违背了真神的旨意,真神必将降下天谴,
 * 使其天天爆零
 * 我不由自主地膜拜真神sqy。
 * Author: RainAir
 * Time: 2019-10-21 15:25:35
 */
#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cstdio>
#include <bitset>
#include <vector>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <map>
#include <set>

#define fi first
#define se second
#define U unsigned
#define P std::pair
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(int i = a;i <= b;++i)
#define ROF(i,a,b) for(int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
#define int LL
int k,x,n,m;
const int MAXN = 50+5;

struct Node{
    int l,cnt,r;
    // 1:A 2:B 3:others

    Node(int l=0,int cnt=0,int r=0) : l(l),cnt(cnt),r(r) {}

    friend Node operator + (const Node &a,const Node &b){
        Node res;res.cnt = a.cnt+b.cnt;
        res.l = a.l;res.r = b.r;
        if(a.r == 1 && b.l == 2) res.cnt++;
        return res;
    }
}f[MAXN];

inline void calc(){
    FOR(i,3,k) f[i] = f[i-2]+f[i-1];
}

signed main(){
    scanf("%lld%lld%lld%lld",&k,&x,&n,&m);
    FOR(i,0,n/2){
        FOR(j,0,m/2){
            FOR(a,0,1) FOR(b,0,1) FOR(c,0,1) FOR(d,0,1){
                if(i2+a+b > n || j2+c+d > m) continue;
                f[1] = Node(a?2:3,i,b?1:3);
                f[2] = Node(c?2:3,j,d?1:3);
                calc();
                if(f[k].cnt == x){
                    if(a) putchar('C');
                    FOR(k,1,i) putchar('A'),putchar('C');
                    FOR(k,i*2+a+1,n-b) putchar('X');
                    if(b) putchar('A');
                    puts("");
                    if(c) putchar('C');
                    FOR(k,1,j) putchar('A'),putchar('C');
                    FOR(k,j*2+c+1,m-d) putchar('X');
                    if(d) putchar('A');
                    puts("");
                    return 0;
                }
            }
        }
    }
    puts("Happy new year!");
    return 0;
}
Last modification:April 7th, 2020 at 10:14 pm
如果觉得我的文章对你有用,请随意赞赏