vjudge 链接
点开题目看困了先睡了一觉。
睡醒了阅读一遍题目以为是组合数学吓哭了跑去看别的题了。
回来了之后一秒看出来是 DP,然后花了十五分钟推了个错误的式子,推累了歇了会儿。
真不喜欢写 DP 于是开始乱搞,还真让我搞出来了。
这我高低写篇题解纪念一下,以下是我的科研成果。
思路
首先相邻的单词如果是一样的是不会对答案产生贡献的,所以我们只考虑这个句子中每个相邻单词都不同的小的句子。方便起见,我们定义一个没有两个相同的单词相邻的句子为好句子。
显然这些好句子之间是互不影响的,我们设一个长度为 \(x\) 的好句子产生的答案为 \(f(x)\),一个完整句子的答案就是找出的所有的 \(x\) 的 \(f(x)\) 的乘积,那我们就需要求出 \(f(x)\) 的值。
然后。。。好像不会了。
别急我们先手模两组数据:
input:
4
n o i p
output:
5input:
6
yi yi si wu yi si
output:
8
根据上面的定义,第一个数据的答案就是 \(f(4) = 5\),第二个是 \(f(5) = 8\)。
有些熟悉?这非常斐波那契。
虽然多手模几组就能发现确实如此,但是教练有言曰:棍母。其实我忘了是什么,反正大概意思是结论的证明非常重要,因此我们证明一下。
对于上面的第一个样例,假设我们知道了当 \(x\) 小于 \(4\) 时所有的 \(f(x)\) 值,我们考虑如何用已知值推出当前值。
我们尝试分割,得到 n | o i p。
发现此时的答案就是 \(f(1) * f(x - 1) = f(x - 1)\),很好记录下来。
但是上面的分法遗漏了第一个单词交换的情况,那我们将它变成这样:o n | i p。
左半部分是固定的,我们只计算右半部分,容易发现此时答案是 \(f(x - 2)\)。
整理一下,得到 \(f(x) = f(x - 1) + f(x - 2)\),就是斐波那契数列。
然后我们就完美解决了这道题!
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;const int MN = 1e5 + 3, mod = 1e9 + 7;
int n, ans = 1;
string s[MN];
vector<int> ve;int f[MN];
void f_fir() {f[1] = 1, f[2] = 2;for (int i = 3; i <= n; i++)f[i] = (f[i - 1] + f[i - 2]) % mod;
}signed main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);cin >> n;f_fir();for (int i = 1; i <= n; i++) cin >> s[i];int tmp = 1;bool fl = 0;for (int i = 2; i <= n; i++) {if (s[i] == s[i - 1]) {if (fl) ve.push_back(tmp), tmp = 1, fl = 0;}else tmp++, fl = 1;}if (fl) ve.push_back(tmp);for (int x : ve) ans = (ans * f[x]) % mod;cout << ans << "\n";return 0;
}