阿里淘天2023秋招-讨厌鬼的排列(map)
讨厌鬼有一个长度为n的数组,他想知道这个数组有多少个子序列是一个排列?
子序列的定义:数组删除若干个元素(也可以不删)后得到的新数组。
排列的定义:长度为m的数组,1到m每个元素都出现过,且恰好出现1次。
输入
第一行输入一个整数n (\(1 < n < 10^5\))
第二行输入n个整数\(a_i\) (\(1 < a < 10^9\))
输出
一行一个整数,表示有多少个子序列是一个排列。由于答案过大,请将答案对\(10^9+7\)取模后输出
样例输入
6
1 1 5 2 3 4
样例输出 复制
10
提示
符合要求的子序列有:{1},{1},{1,2},{1,2},{1,2,3},{1,2,3},{1,2,3,4},{1,2,3,4},{1,5,2,3,4},{1,5,2,3,4}共10个
其实仔细考虑一下这个题和顺序没有什么关系的。所以可以之间拍个序。
然后就是哈希表map了,我们定义一个cnt[i]代表i的个数,sum[i]代表[1..i]的个数
举个例子:
1 1 2 2 3 3
1有两个,cnt[1]=2;sum[1]=2,
2有两个,cnt[2]=2,sum[2]=cnt[2] * sum[1]=4,那么[1,2]的排列就是cnt[2] * sum[1],就是2的个数乘前面1的排列的个数
3有两个,cnt[3]=2,sum[3]=cnt[3] * sum[2]=8,也就是3有两个,然后[1,2]的排列有四种,那么[1,2,3]的排列就有8种
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<map>
typedef long long ll;
using namespace std;
const int maxn=1e6+100;
const int mod=1e9+7;
ll a[maxn];
map<int,ll>cnt,sum;
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
cnt[0]=1;
sum[0]=1;
for(int i=1;i<=n;i++){
cnt[a[i]]++;
sum[a[i]]=(cnt[a[i]]*sum[a[i]-1])%mod;
}
ll ans=0;
for(int i=1;i<=n;i++){
ans=(ans+sum[i])%mod;
}
cout<<ans<<endl;
}