您的位置:首页 > 其它

hdu 4045 Machine scheduling 组合数学

2013-07-27 13:51 190 查看
题意是 有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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: