Lenny's Lucky Lotto Lists
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2191 | Accepted: 953 |
Description
Lenny likes to play the game of lotto. In the lotto game, he picks a list of N unique numbers in the range from 1 to M. If his list matches the list of numbers that are drawn, he wins the big prize.
Lenny has a scheme that he thinks is likely to be lucky. He likes to choose his list so that each number in it is at least twice as large as the one before it. So, for example, if N = 4 and M = 10, then the possible lucky lists Lenny could like are:
1 2 4 8
1 2 4 9
1 2 4 10
1 2 5 10
Thus Lenny has four lists from which to choose.
Your job, given N and M, is to determine from how many lucky lists Lenny can choose.
Input
There will be multiple cases to consider from input. The first input will be a number C (0 < C <= 50) indicating how many cases with which you will deal. Following this number will be pairs of integers giving values for N and M, in that order. You are guaranteed that 1 <= N <= 10, 1 <= M <= 2000, and N <= M. Each N M pair will occur on a line of its own. N and M will be separated by a single space.
Output
For each case display a line containing the case number (starting with 1 and increasing sequentially), the input values for N and M, and the number of lucky lists meeting Lenny's requirements. The desired format is illustrated in the sample shown below.
Sample Input
3
4 10
2 20
2 200
Sample Output
Case 1: n = 4, m = 10, # lists = 4
Case 2: n = 2, m = 20, # lists = 100
Case 3: n = 2, m = 200, # lists = 10000
Source
Regionals 2004 >> North America - Greater NY
Regionals 2004 >> North America - North Central NA
Regionals 2004 >> North America - Pacific Northwest
问题链接:POJ2193 ZOJ2193 UVALive3144 Lenny's Lucky Lotto Lists
问题简述:
用1-M的数来填N长度的序列(不重复)...保证每个数字不小于前一个的两倍...问一共能有多少种序列满足条件?
问题分析:
这是一个DP问题。这类问题的关键要解决状态转换方程以及初始值,这样就可以进行计算了。
假设f(n, m)表示从m个数中选择n个,使之满足后一个是前一个至少2倍,则对于数m,则有2中情况:
1. 选择m,则需要从1~m/2中选择n-1个数
2. 不选择m,则需要从1~m-1中选择n个数
由此得到f(n, m) = f(n-1, m/2) + f(n, m-1)。这是状态转换方程。
另外,对于函数f(n, m),若n=1则f(n, m)=m。这是初始值。
基于以上的递推式,可以用DP实现。
程序说明:
UVALive3144的输出格式不同。
题记:(略)
参考链接:(略)
AC的C++语言程序(POJ2193和ZOJ2193,打表)如下:
/* POJ2193 ZOJ2193 Lenny's Lucky Lotto Lists */
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N = 10;
const int M = 2000;
LL f[N + 1][M + 1] = {0};
void maketable()
{
for(int i = 1; i <= M; i++)
f[1][i] = i;
for(int i = 2; i <= N; i++)
for(int j = 1 << (i - 1); j <= M; j++)
f[i][j] = f[i][j - 1] + f[i - 1][j >> 1];
}
int main()
{
maketable();
int c, caseno = 0;
scanf("%d", &c);
while(c--) {
int n, m;
scanf("%d%d", &n, &m);
printf("Case %d: n = %d, m = %d, # lists = %lld\n", ++caseno, n, m, f[n][m]);
}
return 0;
}
AC的C++语言程序(UVALive3144,打表)如下:
/* UVALive3144 Lenny's Lucky Lotto Lists */
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N = 10;
const int M = 2000;
LL f[N + 1][M + 1] = {0};
void maketable()
{
for(int i = 1; i <= M; i++)
f[1][i] = i;
for(int i = 2; i <= N; i++)
for(int j = 1 << (i - 1); j <= M; j++)
f[i][j] = f[i][j - 1] + f[i - 1][j >> 1];
}
int main()
{
maketable();
int c, caseno = 0;
scanf("%d", &c);
while(c--) {
int n, m;
scanf("%d%d", &n, &m);
printf("Data set %d: %d %d %lld\n", ++caseno, n, m, f[n][m]);
}
return 0;
}
AC的C++语言程序(POJ2193和ZOJ2193,递归)如下:
/* POJ2193 ZOJ2193 Lenny's Lucky Lotto Lists */
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N = 10;
const int M = 2000;
LL f[N + 1][M + 1] = {0};
LL dp(int n, int m)
{
if(n == 1)
return m;
else if(1 << (n - 1) > m)
return 0;
else if(f[n][m])
return f[n][m];
else
return f[n][m] = dp(n - 1, m >> 1) + dp(n, m - 1);
}
int main()
{
int c, caseno = 0;
scanf("%d", &c);
while(c--) {
int n, m;
scanf("%d%d", &n, &m);
printf("Case %d: n = %d, m = %d, # lists = %lld\n", ++caseno, n, m, dp(n, m));
}
return 0;
}
AC的C++语言程序(UVALive3144,递归)如下:
/* UVALive3144 Lenny's Lucky Lotto Lists */
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N = 10;
const int M = 2000;
LL f[N + 1][M + 1] = {0};
LL dp(int n, int m)
{
if(n == 1)
return m;
else if(1 << (n - 1) > m)
return 0;
else if(f[n][m])
return f[n][m];
else
return f[n][m] = dp(n - 1, m >> 1) + dp(n, m - 1);
}
int main()
{
int c, caseno = 0;
scanf("%d", &c);
while(c--) {
int n, m;
scanf("%d%d", &n, &m);
printf("Data set %d: %d %d %lld\n", ++caseno, n, m, dp(n, m));
}
return 0;
}