zoukankan      html  css  js  c++  java
  • CF1462E2 Solution

    题目链接

    题解

    容易想到,因为选出的m个数与在原序列中的顺序无关,所以可以将(a)序列排序,然后找到每一个满足最大值与最小值的差(le k)的区间,排列组合选出(m)个数即可。具体实现的问题有两个:找到区间与排列组合。

    找到区间:进一步分析可得,我们并不需要这个区间的左右端点,只要知道其中元素的个数。因此可以用(sum)数组记录(a)数组中(le i)的数的个数,因为(a[i]le n)不用离散化,前缀和预处理即可。然后枚举区间的右端点,利用(sum)数组求出(ge a[i]-k)的数的个数。

    排列组合:如果在组合函数中每次都计算一遍阶乘的话时间复杂度为(O(n^2)),会TLE。因此需要预处理出所有可能用到的阶乘,为了优化常数,下面的代码中也处理了阶乘的乘法逆元。

    AC代码

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=2e5+10,mod=1e9+7;
    int a[N],fac[N],inv[N],sum[N];
    //fac[i]:i的阶乘; inv[i]:i阶乘的逆元; sum[i]:a数组中<=i的数的个数
    int qpow(int x,int y)
    {
    	int ans=1;
    	while(y)
    	{
    		if(y&1) ans=(ans*x)%mod;
    		x=(x*x)%mod; y>>=1;
    	}
    	return ans;
    }//快速幂(费马小定理求乘法逆元)
    void init()
    {
    	fac[0]=inv[0]=1;
    	for(int i=1;i<=N;i++) fac[i]=(fac[i-1]*i)%mod;
    	for(int i=1;i<=N;i++) inv[i]=qpow(fac[i],mod-2);
    }//预处理
    int C(int n,int m) 
    {
    	if(m>n || m<0) return 0;
    	return (((fac[n]*inv[m])%mod)*inv[n-m])%mod;
    }//组合函数
    signed main()
    {
    	init();
    	int t,k,n,m;
    	scanf("%d",&t);
    	while(t--)
    	{
    		scanf("%lld%lld%lld",&n,&m,&k);
    		for(int i=0;i<=n;i++) sum[i]=0;
    		for(int i=1;i<=n;i++) {scanf("%d",&a[i]); sum[a[i]]++;}
    		for(int i=1;i<=n;i++) sum[i]+=sum[i-1];
    		sort(a+1,a+n+1);
            //寻找区间+统计答案
    		int ans=0;
    		for(int i=n;i>=1;i--)
    		{
    			if(a[i]>k) ans+=C(i-sum[a[i]-k-1]-1,m-1),ans%=mod;
    			else ans=(ans+C(i-1,m-1))%mod;
    		}
    		printf("%d
    ",ans);
    	} 
    	return 0;
    }
    
  • 相关阅读:
    面试系列三 如何保证消息不被重复消费
    面试系列二 消息队列的高可用性
    面试系列一 消息队列
    springcloud系列15 bus的使用
    C++ 参数传值 与 传引用
    [转] 写给立志做码农的大学生
    Python format 格式化函数
    [3] TensorFlow 深层神经网络
    [2] TensorFlow 向前传播算法(forward-propagation)与反向传播算法(back-propagation)
    Python 闭包
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14220567.html
Copyright © 2011-2022 走看看