ex_Asbable 一个蒟蒻OIer

20220320校内考试 T2 string 题解

2022-03-20
ex_Asbable


20220320校内考试 T2 string 题解

题目描述

给出 n 以及 n 个单词(仅包含小写字母)形成一个句子,现打乱这个句子,但是对于任意单词,在原句子和乱序句子中第 i 次 出现的位置不会相差超过1。

求有多少个这样的乱序句子,对1000000007取模。

解法

首先,由“在原句子和乱序句子中第 i 次 出现的位置不会相差超过1”中,就可以知道,只用在原序列中判断是否交换相邻两数就好了。

既然如此,发现前 i 个单词的合法乱序个数不会受到后面单词的影响,故无后效性。

所以自然而然想到 dp 。

怎么设计状态?

很简单,设 dp[i] 表示前 i 个单词的合法乱序句子个数对1000000007取模的值。

故若当前单词与上一个单词不同的话(交换会使序列改变),则dp[i]=dp[i-1]+dp[i-2]

反之,若相同,则dp[i]=dp[i-1](因为此时交换不影响结果,不需更新)

总结一下:

dp[i]=dp[i-1]+dp[i-2](a[i]!=a[i-1])

dp[i]=dp[i-1](a[i]==a[i-1])

别忘了取模

CODE

const ll mn=1e5+10;
const ll mm=1e5+10;
const ll mod=1000000007;
const ll inf=0x3f3f3f3f;
const ll fni=0xc0c0c0c0;
ll n,dp[mn];string s[mn];
inline void read_init(){
    n=read<ll>();
    for(ll i=1;i<=n;i++)
        cin>>s[i];
}
int main(){
//    freopen("string17.in","r",stdin);
//     freopen("string.out","w",stdout);
    read_init();
    dp[0]=1;
    for(ll i=1;i<=n;i++)
        dp[i]=(dp[i-1]+(s[i]==s[i-1]?0:dp[i-2]))%mod;
    write(dp[n]%mod,1);
    return 0;
}

Similar Posts

Comments