Description:
最近Kfc新开了个KFC,该KFC提供N种食物,分别用1-N给这些食物编号,食物的价格与其编号有关,满足第K种食物的价格为2^(K-1),例如:
食物的编号 1 2 3 4 5 6 7 8 9 10……
价格 1 2 4 8 16 32 64 128 256 512 ……
每位顾客最多可以选择L种食物,且每种食物仅一份。
当顾客选择食物时,他会说:我要第M便宜的食物组合。
Kfc的工作就是计算第该食物组合的价格。
一样食物都不要也是一种组合,因此第1便宜的食物组合价格为0。
Input:
一行,包含三个整数N (1<=N<=30),,L (1<=L<=N),M,用一个空格隔开。数据保证存在第M便宜的食品组合。
Output:
一行,包含一个整数P,P为第M便宜的食品组合的价格。
Sample Input
5 3 19
Sample Output
19
题目分析:
显然的二进制+组合数。用一种食物来代表二进制中的一位。逐位确定二进制数,求解。
代码:
/*
2016.9.26 BulaBulaCHN
*/
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<iostream>
#define min(a,b) ((a)<(b)?(a):(b))
#define min(a,b) ((a)>(b)?(a):(b))
using namespace std;
int l,n,m;
int cc[30][30];
int ans;
int c(int n,int m)
{
if(n==0) return 1;
if(m==0) return 1;
if(m==1) return n;
if(m==n) return 1;
if(cc[n-1][m-1] && cc[n-1][m]) return cc[n][m]=cc[n-1][m-1]+cc[n-1][m];
if(cc[n][m]) return cc[n][m];
return cc[n][m]=c(n-1,m-1)+c(n-1,m);
}
int main()
{
freopen("kfc.in","r",stdin);
freopen("kfc.out","w",stdout);
scanf("%d%d%d",&n,&l,&m);
if(m==1) {cout<<0; return 0;}
int last=l;
int lnum=m-1; //应在答案的数字之前的商品组合的个数
int sum=1;
while(1)
{
int flag=1;
sum=1;
for(int pos=0;pos<=n;pos++)
{
int f=0;
for(int i=0;i<=min(last-1,pos-1);i++) f+=c(pos-1,i); //计算最高位为pos位时的方案数
if(sum+f>lnum) {flag=pos; break;}
if(sum+f==lnum) {sum+=f; flag=pos+1; break;} //特殊处理取最后一位
sum+=f;
}
ans|=(1<<(flag-1)); //统计答案
lnum-=sum;
last--;
if(lnum==0) break; //找到了所有应在答案之前的数字
}
cout<<ans<<endl;
return 0;
}