题解: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;
}


浙公网安备 33010602011771号