加载中...

题解:AT_arc077_b [ABC066D] 11

本题是一个比较板的组合题。

由于一共有 \(n + 1\) 个元素,但在 \(1\)\(n\) 之间每个数都至少出现一次,也就是说至少会有一个数字重复。

那这样就很简单了。我们设重复元素最开始出现的地方为 \(l\), 第二次出现的地方为 \(r\),那么出现重复子串的情况就是在 \(l\) 左边、\(r\) 右边出现的字符串中间是 \(l\)\(r\) 其中一个。

可能有点抽象,画图理解一下。

为了区分,\(l\) 左边为蓝色,\(r\) 右边为红色。那么重复的情况大致就是这样。

根据容斥原理,我们可以用全部的子串数量减去不合法的子串数量。

可以得出答案为 \(C^{k}_{n + 1} - C^{k - 1}_{(l − 1) + (n - r + 1)}\)

#include<iostream>
using namespace std;

const int N = 1e5 + 5;
const int mod = 1e9 + 7;

long long fact[N], infact[N];
int a[N], l, r, x, n;

long long ksm(long long x, long long n){
	long long sum = 1;
	x %= mod;
	while(n){
		if(n & 1) sum = sum * x % mod;
		x = x * x % mod;
		n >>= 1;
	}
	return sum % mod;
}

long long C(int n, int m){
	if(n < m) return 0;
	return fact[n] * infact[m] % mod * infact[n - m] % mod;
}

int main(){
	fact[0] = infact[0] = 1;
	for(int i = 1; i <= N; i++){
		fact[i] = fact[i - 1] * i % mod;
		infact[i] = infact[i - 1] * ksm(i, mod - 2) % mod;
	}
	cin >> n;
	for(int i = 1; i <= n + 1; i++){
		scanf("%d", &x);
		if(a[x] == 0) a[x] = i;
		else{
			l = a[x], r = i;
			break;
		}
	}
	for(int i = 1; i <= n + 1; i++){
		long long ans = C(n + 1, i);
		cout << (ans - C(n + l - r, i - 1) + mod) % mod << endl;
	}
	return 0;
}

posted @ 2025-11-17 18:53  碎碎念的女巫  阅读(4)  评论(0)    收藏  举报