POJ2193 ZOJ2193 UVALive3144 Lenny's Lucky Lotto Lists【DP】

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

Pacific Northwest 2004

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;
}

猜你喜欢

转载自blog.csdn.net/tigerisland45/article/details/81989500
今日推荐