周赛F-诺基亚(hard version)

诺基亚(hard version)
比赛题目
时间限制:C/C++ 1000MS,其他语言 2000MS
内存限制:C/C++ 256MB,其他语言 512MB

描述

 

今天小c学长买盲盒中了一个诺基亚,于是他对着这诺基亚研究了起来,他突发奇想想到了一种玩法。我们都知道诺基亚的一个按键可以按出多个字母,于是小c学长规定一个按键上的第几个字母就需要按几次那个数字才能出现(例如2上的字母有a,b,c,我们要a就要按1次2,b要按2次2,c要按3次2)。
小c学长觉得之前的玩法不够有趣,于是他换了一种玩法,将条件和答案进行了颠倒,但是发现颠倒后的答案就不唯一了,于是他希望知道这个按键方式到底能代表多少中字符串。(答案可能有点大,请模1e9+7后输出)RC.jpg

 

输入描述

 

一个整数t,代表有t组样例
每组样例第一行一个n,代表按键字符串长度
第二行n个字符,代表小c的按键顺序。
(保证所有的n加起来不超过1e5,且字符串只包含’2’-‘9’)

 

输出描述

 

每组样例输出一整数,表示这个按键方式对应有多少种字符串。
(请模1e9+7后输出)

 

用例输入 1 

3
5
22233
3
222
3
232

用例输出 1 

8
4
1

用例输入 2 

1
12
222222222222

用例输出 2 

927

提示

 

第一组样例解释,可能的字符串有"aaadd", “abdd”, “badd”, “cdd”, “aaae”, “abe”, “bae” 和 “ce” ,所以答案是8.

这是一个很痛苦的题目,对于新手而言。需要用到一点暴力跑程序去找规律,不难发现,除了7和9以外,剩下的数字都只对应了3个字母,:

输入字母 a :按键 2

输入字母 b :按键 22

输入字母 c :按键 222

而按键数字表示的字母可能性却很多:

按键 2 可能表示:a 共 1 种

按键 22 可能表示:aa, b 共2种

按键 222 可能表示:aaa, ba, ab, c 共 4 种

不难发现,这是一个爬楼梯增强版(其实也可以通过写一个暴力程序跑出规律得出结论),当前数字和上一个数字相同的时候,到达当前位置的方案数可以由上个位置和上上个位置转移过来,那么可以得出递归式子:f(i)=f(i−1)+f(i−2)+f(i−3),[i>3],那么7和9也是相同的规律,得出f(i)=f(i−1)+f(i−2)+f(i−3)+f(i-4),[i>4],因为字符串长度最长1e5,我们可以预处理出两个递归式的前1e5的值的和,那么开始遍历字符串,先初始化一个ans为1,然后每次出连续相同字符的长度,然后将预处理对应的值乘进ans里。以上来自我们学长。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=2e5+10;
typedef long long ll;
#define endl "\n"
ll unusual[N],usual[N];

int main(){
    int t;
    cin>>t;
    usual[1]=1,usual[2]=2;usual[3]=4;//注意别放在while里面了哦,我就直接wa了9次才发现我是一个大怨种。。。
    for(int i=4;i<=100001;i++)
        usual[i]=(usual[i-1]+usual[i-2]+usual[i-3])%mod;
    unusual[1]=1,unusual[2]=2,unusual[3]=4,unusual[4]=8;
    for(int i=5;i<=100001;i++)
        unusual[i]=(unusual[i-1]+unusual[i-2]+unusual[i-3]+unusual[i-4])%mod;
    while(t--){
        ll n;
        cin>>n;
        string str;
        cin>>str;
        ll ans=1;
        for(int i=0;i<str.length();){
            ll num=i,sum=0,temp;
            while(num<str.length()&&str[i]==str[num]){
                num++;
                sum++;
            }
            if(str[i]=='7'||str[i]=='9')temp=unusual[sum];
            else temp=usual[sum];
            i=num;
            ans=(ans*temp)%mod;
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

posted @ 2022-05-16 22:54  JerryTang菜菜  阅读(45)  评论(0)    收藏  举报