小红的排列生成
[题目链接](https://www.nowcoder.com/practice/94c209756a8a4d3085ff64d62a4bb6fb)
思路
给定数组 ,每次操作可以选一个元素加 1(可操作任意次)。问最终能形成多少种不同的
的排列。
关键观察
一个排列 能被生成,当且仅当对每个位置
,都有
(因为只能加不能减)。
所以问题转化为:有多少个 的排列
,满足
对所有
成立?
贪心计数
将 从大到小排序(排序不影响答案,因为排列的分配可以任意对应)。设排序后为
。
按顺序为 分配排列值。对于
,可选的值是
中尚未被使用的值:
对应的候选集大小为
。
- 前面已经分配了
个值,且这些值全部
,所以恰好从候选集中占用了
个。
- 因此第
步的可选数量为
。
由乘法原理,答案为:
$$
如果某一步可选数量 ,则答案为
。
样例验证
,排序后
。
:
:
:
答案 ,与样例一致。
复杂度
- 时间复杂度:
,排序的开销。
- 空间复杂度:
。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
const long long MOD = 1e9 + 7;
int n;
cin >> n;
vector<int> a(n);
for(int i = 0; i < n; i++) cin >> a[i];
sort(a.begin(), a.end(), greater<int>());
long long ans = 1;
for(int i = 0; i < n; i++){
long long choices = (long long)(n - a[i] + 1) - i;
if(choices <= 0){
ans = 0;
break;
}
ans = ans % MOD * (choices % MOD) % MOD;
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
final long MOD = 1000000007L;
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) a[i] = sc.nextInt();
Arrays.sort(a);
for (int i = 0, j = n - 1; i < j; i++, j--) {
int tmp = a[i]; a[i] = a[j]; a[j] = tmp;
}
long ans = 1;
for (int i = 0; i < n; i++) {
long choices = (long)(n - a[i] + 1) - i;
if (choices <= 0) {
ans = 0;
break;
}
ans = ans % MOD * (choices % MOD) % MOD;
}
System.out.println(ans);
}
}

京公网安备 11010502036488号