首页 > 其他 > 详细

[Atcoder Regular Contest 071 F & JZOJ5450]Neutral

时间:2021-01-22 00:07:05      阅读:30      评论:0      收藏:0      [点我收藏+]

题目大意

一个无限长的序列\(a\), 需要满足
1.数列中的每一个数在\(1\)\(n\)之间.
2.对于\(i>=n, j>=n\), \(a_i=a_j\).
3.对于\(i<=n\), \(a_j\)相等. 其中\(j\in(i,i+a_i]\)
求这样的序列的个数.
\(n<=10^6\)

解题思路

发现其实只有\(2n\)项是可能有用的.
然后发现, 如果在\(<=n\)的数中, 有两个相邻的\(>1\)的数, 之后的序列就固定了. 这是特殊情况.
所以这个序列如果没有这种情况, 就可以划成几段: 每一段是\(1\)\(a_i, 1, 1, 1, ...., 1\)(\(a_i\)\(1\), \(a_i>1\))
可以看出一段的长度不等于\(2\).

由于特殊情况, 我们不能正着dp, 只能反着dp. 设\(f_i\)为完成了\(i\)\(n\)的填数后的方案数.

\[f_i=f_{i+1}+f_{i+k+1}+(n-1)^2(1<k<=n) \]

\((n-1)^2\)那一项, 显然是特殊情况. 对于下标大于\(n\)\(f\), 显然是因为\(n\)之后的数也可以填\(1\), 也有贡献.

#include <cstdio>
#include <cstring>
#define N 1000010
#define ll long long
#define MOD 1000000007
#define init(a, b) memset(a, b, sizeof(a))
#define fo(i, a, b) for(int i = (a); i <= (b); ++i)
#define fd(i, a, b) for(int i = (a); i >= (b); --i)
using namespace std;
int n;
ll ans, f[N], s;
inline void upd(ll &x, ll y){x += y; x >= MOD && (x -= MOD);}
int main()
{
	freopen("neutral.in", "r", stdin);
	freopen("neutral.out", "w", stdout);
	scanf("%d", &n);
	f[n + 1] = 1, f[n] = n;
	int k = n;
	fd(i, n - 1, 1)
	{
		f[i] = f[i + 1];
		upd(f[i], s + (--k));
		upd(f[i], 1ll * (n - 1) * (n - 1) % MOD);
		upd(s, f[i + 2]);
	}
	upd(ans, f[1]);
	printf("%lld\n", ans);
	return 0;
}

[Atcoder Regular Contest 071 F & JZOJ5450]Neutral

原文:https://www.cnblogs.com/Martin-MHT/p/14310538.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!