Loading

[ARC071F] Infinite Sequence 题解

[ARC071F] Infinite Sequence

这里提供一个不一样的解法。

我们不难发现,当序列相邻两个值 \(x,y\) 都大于 \(1\) 时,那么序列从 \(x\) 开始会变成 \(x,y,y,y,y,y,y,...\)

序列中出现的值大体可以分为 \(3\) 类:

  1. \(1\) (即 \(2 \sim n\)
  2. 非强制 \(1\) (如 \(2\ ,\ 1\ ,\ 1\ ,\ \dot 1\)
  3. 强制 \(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\) 中的任意一个值,一旦两个位置确定,这个序列就已经确定了,可以直接加入答案
有转移:

\[(n - 1) \times f_{i,0} \rightarrow^+ ans (\rightarrow^+\ 表示累加) \]


\(i + 1\) 位为 非 \(1\) 时,第 \(i\) 位只能是 \(1\) (因为为 非 \(1\) 的答案已经加入进答案中了),
并且 非 \(1\)\((n - 1)\) 种选择(即 \(2 \sim n\)
有转移:

\[(n - 1) \times (f_{i,1} + f_{i,2}) \rightarrow f_{i + 1,0} \]


\(i + 1\) 位为 非强制 \(1\) 时,第 \(i\) 位只能为 强制 \(1\) 的结尾 或 强制 \(1\)
故有转移:

\[(f_{i,1} + f_{i,2}) \rightarrow f_{i,1} \]


因为当 \(i + 1\) 位为 强制 \(1\) 的结尾 时,我们要找哪个位置的 非 \(1\) 导致了 \(i + 1\) 位为 强制 \(1\) 的结尾,即我们要考虑 \(f_{i + 1,2}\) 能从哪里转移过来

因为序列中的值 \(\in \{1,2,...,n\}\)

也就是说,从哪都可以转移!

那么关键就是转移多少?

仔细观察,可以发现,见下图:
pic

只有当第 \(j\) 位为 \(1\) 时,才能在第 \(j + 1\) 位能且仅能找到一个 \(k\) 使得 \(i + 1\) 为 强制 \(1\) 的结尾

因为 强制 \(1\) 的概念只有出现非 \(1\) 才存在,所以 \(j\)\(i + 1\) 至少相距 \(4\),即 \(j \leq i - 2\),如图:

pic

那么有转移:

\[\sum_{0\leq j \leq i - 2} (f_{j,1} + f_{j,2}) \rightarrow f_{i + 1,2} \]

这里用一个 \(cnt\) 记录一下 \(f_{j,1} + f_{j,2}\) 的前缀和就可以在 dp 中 \(O(1)\) 转移了

那么转移部分就结束了。


接下来为 统计答案

我们考虑最后一位的值:

  1. 最后一位是 (第 \(n - 1\) 位 为 \(1\) 的)非 \(1\),即

    \[f_{n,0} \rightarrow^+ ans \]

  2. 最后一位是 非强制 \(1\),即

    \[ f_{n,1} \rightarrow^+ ans \]

  3. 最后一位是 强制 \(1\) 的结尾,即

    \[ f_{n,2} \rightarrow^+ ans \]

  4. 最后一位是 强制 \(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;
}

posted @ 2024-07-26 21:26  MingJunYi  阅读(24)  评论(0编辑  收藏  举报