昨晚刚刚打了div2,又一次体验了坐牢的感觉/(ㄒoㄒ)/
第二天打起精神来看题解弥补一下,首先就选择了这道题(因为我在这道题上wa了4次)
这道题有意思哈它是Div1里的A题,也是Div2里的C题,难度大概可以估算出来了
话不多说,先来看题:
题目(链接Problem - A - Codeforces):
题目的大致意思就是给定两个数组a和b,问若对a重新排序使得ai>bi,有多少中可能的重排方式。
题意很容易理解,但是要如何操作呢?
最初我的想法是找出每一个bi能在a中找到的大于它的数的数量,但后来发现会有重复计数的情况,加之比赛时间很晚了大脑运转不是很稳定,没有想出合适的解决方案...
赛后再仔细想想,这道题其实并不难,运用的组合数学的知识(即使不知道什么是组合数学也完全不影响做题,逻辑理解了就好)
题目分析:
1.首先我们需要明确,b数组的顺序不影响最终结果(这一点很重要)对b数组进行sort排序能够帮助我们简化思路。
2.为了寻找a数组中能够满足大于bi的所有可能元素,我们考虑对a数组进行排序来简化查找。
具体操作(划重点,要好好理解):
①对数组a进行升序排列,对数组b进行降序排列。对数组b从下标0开始遍历,针对每一个b[i],运用upper_bound函数查找到a中第一个大于b[i]的元素的下标,从而求出a中大于b[i]的元素的个数
我们暂且将这些个数存在一个vector<vector<int>> c中,c[i]存放a中大于b[i]的元素的个数,c[i][j]存放这些元素本身(实际代码并不需要创建这样一个容器,这里只是方便解释)
②通过一定的逻辑分析我们不难发现得到的c[i]是降序的,且c[i+1]中的元素包含c[i]中的元素。这就意味着在分析b[i+1]如何在c[i+1]中对应取值时,b[i]可以认定已从c[i+1]中选择好了一个值。此时b[i+1]可以选择的数只有c[i+1]-i个
③最终结果只需将每次求出的c[i+1]-i相乘即可,不要忘记对答案取模。为了避免数值过大我们最好在每相乘一次就取一次模
C++代码:
#include<bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define startt ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define inf 0x3f3f3f3f
using namespace std;
const int MOD = 1e9 + 7;
int main() {
startt;
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int a[n];
int b[n];
rep(i,n)cin>>a[i];
rep(i,n)cin>>b[i];
sort(a,a+n);//数组a升序
sort(b,b+n,greater<int>());//数组b降序
long long ans = 1;
rep(i,n){
int temp = sizeof(a)/sizeof(a[0])-(upper_bound(a,a+n,b[i])-a);
//sizeof(a)/sizeof(a[0])是数组a大小,upper_bound(a,a+n,b[i])-a是a中第一个大于b[i]的数的下标
//二者相减就是b[i]可以对应的数的个数
ans = ans*max(temp-i,0) % MOD;
//temp-i就是在b[i]前面的数都选择完后,b[i]还能选的数的个数
//若temp-i<0,就是没有选择,直接取0
}
cout<<ans<<endl;
}
return 0;
}
跑出来是这个结果:
很简单的一道题,还是蛮好理解的~
Ummmm学校里最近开设十分密集的java软件开发课,每天都排的满满的╮(╯o╰)╭
第一次写博客没有太多经验,对题目的解释可能也会出现一些不太清除或者错误的地方,还请大家指正!