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; }