Codeforces Round #873(Div1)A题题解——组合数学(C++)

1 篇文章 0 订阅
1 篇文章 0 订阅

昨晚刚刚打了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╰)╭

第一次写博客没有太多经验,对题目的解释可能也会出现一些不太清除或者错误的地方,还请大家指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值