FJUT OJ 2466 T^T的叛乱计划(组合数学)

T^T的叛乱计划

TimeLimit:3000MS  MemoryLimit:64MB
64-bit integer IO format:%lld
已解决 | 点击收藏
Problem Description

话说FJUT_ACM在Home_Z的领导下,日益壮大,在整个FJUT也有了不小的名声。邪恶的T^T不甘受制于人,启动了一个秘密计划,要从Home_Z的手中发动暴乱,从而夺取管理权。

T^T在组织内秘密串通了n个人,并制作了n个绝密令牌,要将n个令牌分给n个人。

为了方便管理,每个令牌上都写了一个数字k,并且每个令牌上的数字互不相同。

每个人在FJUT_ACM内有一个工号z,但是由于各种层级关系混乱,每个人的工号并不是互不相同的。

这就很头疼了。。不能建立一种一一对应的关系。于是T^T想在分发号码牌的时候,必须保证每个人的工号 大于或等于 令牌上的数字。

那么请计算这样分发令牌的话有多少种互不相同的方法。(只要有任意一个人拿到不一样的令牌即为不同的方法)

Input

第一行输入一个T表示测试数据的组数

每组数据第一行是一个n(1<=n<=105)

接下来一行有n个数字表示第i个令牌上的数字ki。

下一行有n个数字表示第i个召集的成员的工号zi。

(1<=ki,zi<=1e9)

Output

每个测试样例先输出"Case #x: A"。x表示当前是第几个测试数据。A表示答案。由于答案会很大,请输出A%(109+7)的结果。

SampleInput
3
5
1 2 3 4 5
1 2 3 4 5
2
1 3
2 2
3
2 3 4
6 3 5
SampleOutput
Case #1: 1
Case #2: 0
Case #3: 4

分析:
对于工号较小的人能够发的令牌,对于编号较大的人也一定能发布。
所以能够发布的令牌数量随工号的增大而增大。
比如对于最小的工号能够颁发 r个,第二小的工号能够颁发k个(k一定大于等于r)
那么最小的工号,就要在r个中选一个,第二小的工号在(k-1)个中选一个,以此类推
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=1e5+10;
const LL MOD=1e9+7;
LL t,n;
LL a[MAXN];
LL b[MAXN];
int main()
{
    LL Case=0;
    LL ans;
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
      Case++;    
      cin>>n;
      for(int i=1;i<=n;i++)    
       cin>>a[i];
       for(int i=1;i<=n;i++)
       cin>>b[i];
       sort(a+1,a+n+1);
       sort(b+1,b+n+1);     
       int k=1;
       ans=1;
        for(int i=1;i<=n;i++)
        {
           while(k<=n&&a[k]<=b[i])k++;
               ans=ans*(k-i)%MOD;
        }    
        cout<<"Case #"<<Case<<": "<<ans<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/a249189046/p/8444867.html