2020牛客寒假算法基础集训营6 D 重排列

https://ac.nowcoder.com/acm/contest/3007/D
题目描述

一个序列的重排列是指对这个序列中的元素进行若干次(包括0次)交换操作后得到的新序列

在本题中,序列中可能出现重复的数字,他们被视作不同的元素

例如,序列1 1的重排列有两种

现在有两个长度为 N 的非负整数序列 A 和 B,问有多少种 A 的重排列满足对于所有的 1≤i≤N,有Ai≤Bi

由于答案可能很大,你只需要输出答案对1e9+7取模的结果

思路 

算是一个统计题吧。首先可以明确方案数和 b 序列的顺序无关 ,比如 b 是 1 2 3 4和他是4 3 2 1方案数一样,既然这样就可以换个思路考虑。

因为是让A小于B,所以先把序列B按从小到大排序,接下来考虑,B[0]上面对于的A[0]有多少中放的方法,就是上面序列小于等于B[0]的个数,因为小于等于B[0]的一定小于等于B[1],所以现在A[1]的选择是小于等于自己的个数减去1,以此类推。

因此可以先求小于等于每一个位置B[i]A中的个数,然后循环一遍,每个位置的结果是less[i]-i+1,求一个连乘积即可。

#include <bits/stdc++.h>
#define mem(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int n;
ll a[N], b[N];
ll les[N];
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)scanf("%lld", a + i);
	for (int i = 1; i <= n; i++)scanf("%lld", b + i);
	sort(b + 1, b + 1 + n);
	sort(a + 1, a + 1 + n);
	int l = 1;
	les[0] = 0;
	for (int i = 1; i <= n; i++){
		les[i] = les[i - 1];
		for (; l <= n && a[l] <= b[i]; l++){
			les[i]++;
		}
	}
	ll res = les[1] % mod;
	for (int i = 2; i <= n; i++){
		res *= (les[i] - i + 1);
		res %= mod;
	}
	printf("%lld\n", res);
	return 0;
}

 

posted @ 2020-02-15 18:16  correct  阅读(69)  评论(0)    收藏  举报