题意是 有n台机器,从中选出r台机器,满足两台的编号差不小于k , 并将这r台,分成m组, 问有多少种组合方式?
第二部分 就是裸的 第二类斯特林数。
重点是第一部分 :
问题 抽象出来就是 : 从 数字 1 - n 种,选出 r 个 ,相邻的两个差不小于k 。
这个题的解法有两种。 一种是 dp 一个一个递推。
第二种就是 组合公式。 要比第一种方法快的多
解法; 我们选出的 r 个 分别 记为 a1 a2 a3 ...... ar
我们 令 bn 数列, b1 = a1 , b2 = a2 - (k -1) , b3 = a3 - 2( k -1) ..... br = ar - (r-1)*( k -1)
这样 这r 个 ai 和 bi 是一一对应的。 从ai 可以对应到bi ,从bi 可以对应到 ai 。
而 bi 数列中 两项的差大于等于1 。bi数列的组合数 就是 C( n - (r -1 )* ( k -1 ) , r )
求组合数, mod 之后的值, 直接利用逆元 即可求出。
组合数求法
#include <iostream> #include <cstring> #include <cstdio> #define LL long long using namespace std; const LL mod = 1000000007; LL s[1001][1001]; void init(){ memset(s,0,sizeof(s)); s[1][1] =1; for(int i=2;i<= 1000;i++){ for(int j = 1;j<=i;j++){ s[i][j] = s[i-1][j-1] + j* s[i-1][j]; s[i][j]%= mod; } } } LL pow(LL a,LL b){ LL ret = 1; while(b){ if(b&1){ ret *= a; ret %= mod; } a = a*a; a %= mod; b =b>>1; } return ret; } int n , m , r , k ; LL get(){ int a = n - (r-1)*k + r -1; if(r>a)return 0; LL up = 1; for(int i= a- r +1;i<=a;i++){ up *= i; up%= mod; } LL down =1; for(int i=1;i<=r;i++){ down *= i; down %= mod; } down = pow(down ,mod - 2); up = up*down; up%= mod; return up; } void solve(){ LL ans = get(); ans %= mod; LL p= 0 ; for(int i=1;i<= m;i++){ p+= s[r][i]; p%= mod; } ans *= p; ans %= mod; cout << ans <<endl; } int main() { init(); while(~scanf("%d%d%d%d",&n,&r,&k,&m)){ solve(); } return 0; }
#include <iostream> #include <cstring> #include <cstdio> #define LL long long using namespace std; const LL mod = 1000000007; LL s[1001][1001]; void init(){ memset(s,0,sizeof(s)); s[1][1] =1; for(int i=2;i<= 1000;i++){ for(int j = 1;j<=i;j++){ s[i][j] = s[i-1][j-1] + j* s[i-1][j]; s[i][j]%= mod; } } } int n , m , r , k ; LL dp[1001][1001]; LL t[1001]; void init_dp(){ memset(dp,0,sizeof(dp)); for(int i =1;i<=n;i++){ dp[1][i] = 1; } for(int i =2;i<=r;i++){ t[0] = 0; for(int j = 1;j<=n;j++){ t[j] = t[j-1]+dp[i-1][j]; } for(int j = k;j<=n;j++){ if(j>=k){ dp[i][j] = t[j-k]; } dp[i][j] %= mod; } } } void solve(){ init_dp(); LL ans = 0 ; for(int i =r;i<=n;i++){ ans += dp[r][i]; } ans %= mod; LL p= 0 ; for(int i=1;i<= m;i++){ p+= s[r][i]; p%= mod; } ans *= p; ans %= mod; cout << ans <<endl; } int main() { init(); while(~scanf("%d%d%d%d",&n,&r,&k,&m)){ solve(); } return 0; }