dp,斐波那契数列

题意:

图片说明

分析:

我们现列举简单的例子:
图片说明
对第一个例子,he he zhou is watching you
我们简写为: a a b c d e
那么一共有几种呢?
首先自己是一个
然后我们两两交换:
a (b a) c d e a a (c b) d e a a b (d c) e a a b c (d e)
一共四种
尝试交换更多:
a (b a) (d c) e a (b a) c (d e) a a (c b) (e d)
一共三种。
总共八种!

我们看上式似乎发现了什么,对开头的a a明显其中一个是多余的。
那么我们不妨先考虑 a b c d e 即相邻单词都不相同的情况。
这时候我们怎么求呢?
分为两种情况:
1.我们交换前两个元素(b a)那么求的就是 c d e 长度为3的情况的种类
2.我们前两个不交换 那么求的就是 b c d e 长度为4的情况下的种类
如此我们的dp就出来了:
dp[i]表示长度为i的两两不相同的字符串情况种类
动态转移方程:
dp[i] = dp[i-1]+dp[i-2]
有没有发现很眼熟?斐波那契数列!
正好dp[1] = 1,dp[2] = 2

如此我们对于任意字符串假如:
a b c d d d e f g
我们求 a b c d的情况种类dp[4]
求 d e f g 的情况种类dp[4]

答案为:dp[4]*dp[4]
即以出现重复元素为分界点,计算两边的情况再相乘!!

代码如下:

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
typedef long long ll;
const int max_n = 1e5 + 100;
const int mod = 1e9 + 7;
typedef pair<string, int> psi;
psi ward[max_n];
int d[max_n];
int n;

int main() {
    ios::sync_with_stdio(0);
    d[1] = 1;d[2] = 2;
    for (int i = 3;i <= 1e5;i++)
        d[i] = (d[i - 1] + d[i - 2]) % mod;
    int T;cin >> T;
    while (T--) {
        cin >> n;
        ll ans = 1;
        string s1, s2;
        int i = 1;int j;
        for (j = 1;j <= n;j++) {
            cin >> s2;
            if (s2 == s1) {
                ans = ((ans % mod) * (d[j - i] % mod)) % mod;
                i = j;
            }s1 = s2;
        }
        if (i != j - 1) {
            ans = ((ans % mod) * (d[j - i] % mod)) % mod;
        }
        cout << ans << endl;
    }
}