[ARC071F] Infinite Sequence 题解
[ARC071F] Infinite Sequence
这里提供一个不一样的解法。
我们不难发现,当序列相邻两个值 \(x,y\) 都大于 \(1\) 时,那么序列从 \(x\) 开始会变成 \(x,y,y,y,y,y,y,...\)。
序列中出现的值大体可以分为 \(3\) 类:
- 非 \(1\) (即 \(2 \sim n\))
- 非强制 \(1\) (如 \(2\ ,\ 1\ ,\ 1\ ,\ \dot 1\))
- 强制 \(1\) (如 \(2\ ,\ \dot 1\ ,\dot 1,1\))
那么,我们考虑序列第 \(i\) 位的值,写出下列状态和转移:
\(f_{i,0}\) 为 (第 \(i- 1\) 位 为 \(1\)) 第 \(i\) 位为 非 \(1\) 的方案数,
\(f_{i,1}\) 为 第 \(i\) 位为 非强制 \(1\) 的方案数,
\(f_{i,2}\) 为 第 \(i\) 位是 强制 \(1\) 的结尾(如 \(2\ ,\ 1\ ,\ \dot 1\ ,\ 1\)) 的方案数,
因为 非 \(1\) 下一位可以是 \(2 \sim n\) 中的任意一个值,一旦两个位置确定,这个序列就已经确定了,可以直接加入答案
有转移:
当 \(i + 1\) 位为 非 \(1\) 时,第 \(i\) 位只能是 \(1\) (因为为 非 \(1\) 的答案已经加入进答案中了),
并且 非 \(1\) 有 \((n - 1)\) 种选择(即 \(2 \sim n\))
有转移:
当 \(i + 1\) 位为 非强制 \(1\) 时,第 \(i\) 位只能为 强制 \(1\) 的结尾 或 强制 \(1\)
故有转移:
因为当 \(i + 1\) 位为 强制 \(1\) 的结尾 时,我们要找哪个位置的 非 \(1\) 导致了 \(i + 1\) 位为 强制 \(1\) 的结尾,即我们要考虑 \(f_{i + 1,2}\) 能从哪里转移过来
因为序列中的值 \(\in \{1,2,...,n\}\)
也就是说,从哪都可以转移!
那么关键就是转移多少?
仔细观察,可以发现,见下图:
只有当第 \(j\) 位为 \(1\) 时,才能在第 \(j + 1\) 位能且仅能找到一个 \(k\) 使得 \(i + 1\) 为 强制 \(1\) 的结尾
因为 强制 \(1\) 的概念只有出现非 \(1\) 才存在,所以 \(j\) 到 \(i + 1\) 至少相距 \(4\),即 \(j \leq i - 2\),如图:
那么有转移:
这里用一个 \(cnt\) 记录一下 \(f_{j,1} + f_{j,2}\) 的前缀和就可以在 dp 中 \(O(1)\) 转移了
那么转移部分就结束了。
接下来为 统计答案
我们考虑最后一位的值:
- 最后一位是 (第 \(n - 1\) 位 为 \(1\) 的)非 \(1\),即\[f_{n,0} \rightarrow^+ ans \]
- 最后一位是 非强制 \(1\),即\[ f_{n,1} \rightarrow^+ ans \]
- 最后一位是 强制 \(1\) 的结尾,即\[ f_{n,2} \rightarrow^+ ans \]
- 最后一位是 强制 \(1\)(非结尾),由于每一个(不为第 \(n\) 位的)位置都有(\(n - (n - pos) = pos\))个 \(k\) 可以使最后一位为强制 \(1\)(非结尾),
所以有:\[ \sum_{1\leq i < n} (f_{i-1,2} + f_{i - 1,1}) \cdot i \rightarrow^+ ans \]
那么本题就完美结束了!
最后注意一些关于初始化的细节
\(f_{1,0} = (n - 1),f_{1,1} = 1,f_{1,2} = 0\)
因为 第 \(0\) 位也可以 视做有一个强制 \(1\) ,所以 \(f_{0,2} = 1\)
AC-code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int mod = 1e9+7,N = 1e6+5;
int n,dp[N][3],cnt,ans;
signed main() {
n = rd();
dp[1][0] = n - 1;dp[1][1] = 1;dp[1][2] = 0;dp[0][2] = 1;
for(int i = 1;i<n;i++) {
ans = (ans + dp[i][0] * (n - 1) % mod) % mod;
dp[i + 1][0] = (dp[i + 1][0] + (n - 1) * (dp[i][1] + dp[i][2]) % mod) % mod;
dp[i + 1][1] = (dp[i + 1][1] + (dp[i][1] + dp[i][2]) % mod) % mod;
if(i - 2 >= 0) cnt = (cnt + (dp[i - 2][2] + dp[i - 2][1]) % mod) % mod;
dp[i + 1][2] = cnt;
}
for(int i = 1;i<n;i++)
ans = (ans + (dp[i - 1][2] + dp[i - 1][1]) * i % mod) % mod;
ans = (ans + dp[n][0]) % mod;
ans = (ans + dp[n][1]) % mod;
ans = (ans + dp[n][2]) % mod;
wt(ans);
return 0;
}