zoukankan      html  css  js  c++  java
  • 【解题报告】[动态规划] CodingTrip

    原题:

    聪明的猴子

    Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)

    Problem Description

    森林中有一排香蕉树(无限长),一只猴子站在其中一棵树上,猴子在跳跃前要先抽取一张卡片,卡片上写有A+1个自然数,其中最后一个是B,前A个数只能小于等于B,卡片上的数字可以相同。猴子每次跳跃先从卡片上任选一个自然数C,然后向左、或向右跳C棵树。猴子的任务是:跳到与它左边相邻的香蕉树上时,就可以吃掉上面的香蕉。

    例如,当A=2,B=4时,对于卡片(2, 3, 4),猴子就可以吃到香蕉:它可以先向左跳3棵树,再向右跳两棵树。而对于卡片(2, 2, 4),猴子则怎么也不可能跳到它左边相邻的香蕉树上。 

    当确定A和B后,则一共可以有B^A张不同的卡片。问题是,在这所有的卡片中,有多少张可以让猴子完成任务。 

    Input

    第1行k,表示有k组测试数据,k<=100
    第2至k+1行,每行两个自然数A和B,以一个空格分开 (A<= 10 , B <= 20)。

    Output

    共k行,每行的数字代表每组数据中,可以让猴子跳到它左边相邻香蕉树的卡片数。

    Sample Input

    3
    2 3
    4 8
    5 13
    

    Sample Output

    8
    3840
    371292

    =========================================================================================

    解题思路:
    不难得知,要满足猴子能跳到相邻的树上,要满足所有数的最大公约数等于1。
    对于一组数据:{6,8,3,5,10} 要求出它们的最大公约数,可以这么计算: 先计算出gcd(6,8)=2,然后用结果和3计算,即:gcd(2,3)=1。当结果为1时,gcd(1,x)=1。就可以知道,此时满足条件了。要计算满足条件的数据总数,可以这样:递归遍历每一种情况,然后判断该序列的gcd是否等于1。等于1计数。
    题目给的范围是A<= 10 , B <= 20,有B^A种情况,如果一个一个判断过去是一定要超时的。
    因此想到这样的一个优化:
    如果判断到中间某个数时,gcd已经为1了,那么在这种情况下,后面的序列已经不能影响gcd,那么这一类的所有情况都可以,即,如果gcd为1时还剩下n个数没搜索,则该情况下的个数为B^n。
    经过这一步的优化,依然不足以计算出较大的数据。现在就想到了一个记忆化搜索。设dp[x][y]表示当前最大公约数为x,已经选择了y个数时的情况的数量。这时将B这个数当做是第一个数来进入递归,即要求的为dp[B][1]。
    解题代码:
     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<string.h>
     4 using namespace std;
     5 long long a,b,ans;
     6 long long dp[25][15]={0};
     7 long long gcd(long long a,long long b)
     8 {
     9     if(b==0) return a;
    10     return gcd(b,a%b);
    11 }
    12 long long pow(long long a,long long b)
    13 {
    14     long long s=1;
    15     while(b--) s*=a;
    16     return s;
    17 }
    18 int f(long long g,long long k)
    19 {
    20     if(dp[g][k]!=0) {ans+=dp[g][k];return 1;}
    21     if(k>a)
    22     {
    23         /*if(gcd(g,b)==1) ans+=1;*/
    24         return 0;
    25     }
    26     long long ans2=ans;
    27     for(long long i=1;i<=b;i++)
    28     {
    29         long long gg=gcd(g,i);
    30         if(gg==1)
    31         {
    32             ans+=pow(b,a-k);
    33         }
    34         else f(gg,k+1);
    35     }
    36     dp[g][k]=ans-ans2;
    37     return 1;
    38 }
    39 int main()
    40 {
    41     long long k;
    42     cin>>k;
    43     while(k--)
    44     {
    45         cin>>a>>b;
    46         memset(dp,0,sizeof(dp));
    47         ans=0;
    48         f(b,1);
    49         /*for(long long i=1;i<=b;i++)
    50             f(i,2);*/
    51         cout<<ans<<endl;
    52     }
    53 }
    View Code
  • 相关阅读:
    hdu 5366 简单递推
    hdu 5365 判断正方形
    hdu 3635 并查集
    hdu 4497 数论
    hdu5419 Victor and Toys
    hdu5426 Rikka with Game
    poj2074 Line of Sight
    hdu5425 Rikka with Tree II
    hdu5424 Rikka with Graph II
    poj1009 Edge Detection
  • 原文地址:https://www.cnblogs.com/syiml/p/3660125.html
Copyright © 2011-2022 走看看