• Codeforces Round #690 (Div. 3) E2. Close Tuples (hard version) (数学,组合数)


    • 题意:给你一长度为(n)的序列(可能含有相等元素),你要找到(m)个位置不同的元素使得(max(a_{i-1},a_{i_2},...,a_{i_m})-min(a_{i-1},a_{i_2},...,a_{i_m})le k),问你共有多少种不同的元祖满足条件,对答案(mod 1e9+7).
    • 题解:我们可以先用map做桶统计每个数出现的次数,然后枚举([1,n]),用前缀和(pre)统计出现的次数,然后我们再去枚举([1,n]),我们每次将(i)([1,i-1])看成两部分,从(i)([1,i-1])中选数,这样可以做到不重复不漏选,每次枚举从(i)中选的次数和([1,i-1])选的次数求组合数即可.
    • 代码:
    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int t;
    int n,m,k;
    int a[N];
    int f[N],inv[N];
    int pre[N];
    map<int,ll> mp;
    
    int add(int x,int y){
    	x+=y;
    	if(x>=mod) x-=mod;
    	return x;
    }
    
    int mul(int x,int y){
    	return 1ll*x*y%mod;
    }
    
    int fpow(int a,int b){
    	int res=1;
    	while(b){
    		if(b&1) res=mul(res,a);
    		a=mul(a,a);
    		b>>=1;
    	}
    	return res;
    }
    
    int C(int n, int m){
    	if(n<m) return 0;
    	return mul(f[n],mul(inv[n-m],inv[m]));
    }
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	cin>>t;
    
    	f[0]=1;
    	rep(i,1,N-1) f[i]=mul(f[i-1],i);
    	inv[N-1]=fpow(f[N-1],mod-2);
    	per(i,N-2,0) inv[i]=mul(inv[i+1],i+1);
    
    	while(t--){
    		cin>>n>>m>>k;
    
    		mp.clear();
    
    		rep(i,1,n){
    			cin>>a[i];
    			mp[a[i]]++;
    		}
    
    		if(m==1){
    			cout<<n<<'
    ';
    			continue;
    		}
    
    		rep(i,1,n){
    			pre[i]=pre[i-1]+mp[i];
    		}
    	
    		ll ans=0;
    
    		rep(i,1,n){
    			int cur=mp[i];
    			if(!cur) continue;
    			int psum=pre[i-1]-((i-k-1>=0)?pre[i-k-1]:0);
    			rep(j,1,min(cur,m)) ans=add(ans,mul(C(cur,j),C(psum,m-j)));
    		}
    
    		rep(i,1,n) pre[i]=0;
    
    		cout<<ans<<'
    ';
    
    	}
    
        return 0;
    }
    
  • 相关阅读:
    记一次centos7.2下用crontab执行定时任务的过程(初级)
    海外手机号码正则匹配
    装了wamp之后,80端口被占用解决办法
    newtonsoft动态修改JObject
    .net正则提取手机号码,并替换带有手机号码的a标签
    .vs目录有什么用?
    centos7安装nginx-1.13.6 新手入门,图文解析
    centos7安装kafka_2.11-1.0.0 新手入门
    centos7安装apache 新手入门 图文教程
    面向对象——案例练习(4)判断点是否在圆的内部
  • 原文地址:https://www.cnblogs.com/lr599909928/p/14158898.html
Copyright © 2020-2023  润新知