zoukankan      html  css  js  c++  java
  • How Many Sets II

    Description

    给一个集合,一共 n 个元素,从中选取 m 个元素,满足选出的元素中没有相邻的元素,一共有多少种选法。(结果对 p 取模 (1 <= p <= 10^9)

    Solution

    关于新题目:我没有证完,或许不能这样做,这一段可以跳过。

    新题目:给一个集合,一共 n 个元素,从中选取 m 个元素,满足选出的元素相隔的元素个数大于等于 k,一共有多少种选法。(结果对 p 取模 (1 <= p <= 10^9)

    这种题目其实可以直接转换到上面的题目。

    我们设 p 数组为选出来的元素的下标集合。定义 (t[i]=p[i]-(i-1)*k)

    可以发现,每个 (t[i])(t[i-1]) 之间的距离都会比 (p[i])(p[i-1]) 的距离少了 k。(这个地方和【BalticOI 2004】Sequence 的转化是一样哒好吧其实我只是想骗访问量嘿嘿嘿

    而我们先开始要求 (p[i]-p[i-1]>=k+1),所以现在就要求 (t[i]-t[i-1]>=1) 了。(然后,其实我就不会了)

    好了我们回到原题。这里有一种非常巧妙的方法:我们定义年糕精为没有编号的相同的妖怪,一共有 n 个年糕精。先拿出 m 个年糕精,剩下的年糕精形成 (n-m+1) 个空位,我们再把 m 个年糕精放回空位就可以了。这样我们的公式就是 (C(n-m+1,m))。(为什么要定义年糕精为没有编号的相同的妖怪?我们选择了年糕精的空位相当于选择了年糕精的编号,因为整个数列是要保持有序的)

    Code

    #include <cstdio>
    typedef long long ll;
    
    int n, m, mod;
    
    int Inv(int x, int y) {
    	int r = 1;
    	while(y) {
    		if(y & 1)  r = 1ll * r * x % mod;
    		x = 1ll * x * x % mod; y >>= 1;
    	}
    	return r;
    }
    
    int C(const int n, const int m) {
    	if(n < m) return 0;
    	int up = 1, down = 1;
    	for(int i = 1; i <= m; ++ i) {
    		up = 1ll * up * (n - i + 1) % mod;
    		down = 1ll * down * i % mod;
    	}
    	return 1ll * up * Inv(down, mod - 2) % mod;
    }
    
    int Lucas(const int n, const int m) {
    	if(! m) return 1;
    	if(n < m) return 0;
    	return 1ll * Lucas(n / mod, m / mod) * C(n % mod, m % mod) % mod;
    }
    
    int main() {
    	while(~ scanf("%d %d %d", &n, &m, &mod)) printf("%d
    ", Lucas(n - m + 1, m));
    	return 0;
    }
    
  • 相关阅读:
    02-线性结构1 两个有序链表序列的合并
    ScSPM
    中国大学MOOC-陈越、何钦铭-数据结构-笔记
    01-复杂度1 最大子列和问题(剑指offer和PAT)
    Matlab中配置VLFeat
    循环队列实现
    对于利用pca 和 cca 进行fmri激活区识别的理解
    对于利用ica进行fmri激活区识别的理解
    利用spm提供的MoAEpilot听觉数据学习预处理以及单被试glm分析与统计推断
    fsl的feat软件分包使用笔记
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12778723.html
Copyright © 2011-2022 走看看