HDU 4574Bombs

Bombs

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 12   Accepted Submission(s) : 2
Problem Description
  Terrorists are around everywhere, they always make troubles by detonating bombs. The terrorist have some gunpowder to make bombs, different gunpowder has different damage, every kind of gunpowder can use any times, and the power of one bomb is the product of the gunpowder it consists of. Let’s see how they make a bomb.
  At the beginning they decide to use X parts of gunpowder to make a bomb, and then choose X parts of gunpowder, every time the damage of the gunpowder they choose can’t be smaller than the last time they choose excepting the first time. After choosing X parts gunpowder terrorists get gunpowder[1], gunpowder[2] ... gunpowder[X] ( gunpowder[1] <= gunpowder[2] <= ... <= gunpowder[X]), and then mix the X parts gunpowder to generate a bomb with power of the product of the damage of the gunpowder. Terrorists make bombs in some order, if they make bomb_A before bomb_B one of the following conditions should meet.
(1)Terrorists use less parts gunpowder to make bomb_A than bomb_B.
(2)Terrorists both use X parts of gunpowders to make bomb_A and bomb_B. There exist an integer j(j <=X),for all i < j,gunpowder_A[i] = gunpowder_B[i] and gunpowder_A[j] < gunpowder_B[j].
  Now, the police get the gunpowder by some way, police find that the gunpowder’s damage is in the range of A to B(A, B included), police want to know the K-th bomb with the power in the range of L to R(L, R included).
 

Input
  There are multiple cases, the first line is an integer T denoting the number of the case, for each case has five integers A, B, L, R, K in a line. A, B denote the damage range of the gunpowder. L, R denote the power range of the bomb, K denotes the K-th bomb with the power in the range L to R that police want to know. 2<=A <= B<=10^6 1<=L<=R<=10^9 1<=K<=10^6
 

Output
  For each case output in the format in the first line “Case #x: y” x is the case number start from 1, y is the power of the bomb, and the second line with the gunpowder in the order they choose. If there is no more than K bombs in the range of L to R just output one line “Case #x: -1”.
 

Sample Input
4 2 2 1 4 1 2 5 1 4 4 73 23642 12 20903 29401 2 50 1 1000000000 815180
 

Sample Output
Case #1: 2 2 Case #2: 4 2 2 Case #3: -1 Case #4: 59200 4 4 5 20 37 [hint] In the second case we have 4 kinds of gunpowder with damage 2, 3, 4, 5. the first bomb is “2”with power of 2 The second bomb is “3” with power of 3 The third bomb is “4” with power of 4 The fouth bomb is “5” with power of 5 The fifth bomb is “2 2” with power of 2 * 2 = 4 So the 4-th bomb with power in the range of 1 to 4 is “2 2”. [/hint]
 

Source
2013 ACM-ICPC長沙賽區全國邀請賽——題目重現


迷迷糊糊的開始搜索練習,這個是一開始看的題目。

看到的第一個想法,直接暴力搜索,超時!

參考了大神的博客  http://blog.csdn.net/acm_cxlove/article/details/9935667


大致明白了怎麼做。。。首先  按題意,解的數的個數在29個之內

計算出每一個長度所對應的解的個數,然後確定題目所求的答案的長度。但枚舉最後一層時所花費的時間還是太大。。。繼續參考


在再長度n中枚舉第n-1的狀態,就能計算出每一個n-1所對應的解的個數,從而省去了枚舉第n層所花費的時間。。。但還是超時。。。想到剪枝。。不會。。。繼續參考


知道當前層所需要乘出的乘積,即可由乘積求出上界和下界,很重要的剪枝!


接下來。。。看代碼理解吧


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>

using namespace std;
typedef long long LL;
const LL inf = 1000000000LL;

int t;
int A,B,L,R,K;
int tt,summ,aa[50];

int Pow(int a,int b)
{
    int ans=1;
    for(int i=1; i<=a; i++)
    {
        ans*=b;
        if(ans>inf||ans<=0)
            return inf+1;
    }
    return ans;
}

int dfs_len(int c,int a,int b,int l,int r,int k)
{
    if(c==0) return l<=r;
    if(c==1)
    {
        if(l>r)  return 0;
        return max(0,min(b,r)-max(a,l)+1);
    }
    int up=min(b,r/Pow(c-1,a));
    int down=max(a,l/Pow(c-1,b));  //求第C位數的取值範圍  下限爲  down*Pow(c-1,b)  上限  up*Pow(c-1,a)
    int ans=0;
    for(int i=down; i<=up; i++)
    {
        ans+=dfs_len(c-1,i,b,(l+i-1)/i,r/i,k-ans);  //求剩餘c-1位數的乘積  最小乘積爲 l/i  最大乘積爲r/i
        if(ans>k)
            return ans;
    }
    return ans;
}
int ret;
void dfs(int c,int a,int b,int l,int r,int k)
{
    if(c==0)
    {
        return ;
    }
    if (c == 1)
    {
        int num = k + max(l , a) - 1;
        ret = ret * num;
        aa[c] = num;
        return ;
    }
    // 上下界
    int down = max(a , l / Pow( c - 1 , b));
    int up = min (b , r / Pow( c - 1 , a));
    for (int i = down ; i <= up ; i ++)
    {
        int cnt = dfs_len (c - 1 , i , b , (l + i - 1) / i , r / i , k);
        if (k > cnt)
        {
            k -= cnt;
            continue;
        }
        ret = ret * i;
        aa[c] = i;
        dfs (c - 1 , i , b , (l + i - 1) / i , r / i , k);
        return ;
    }
}

int main()
{
    scanf("%d",&t);
    tt=1;
    while(t--)
    {
        scanf("%d%d%d%d%d",&A,&B,&L,&R,&K);
        int i;
        bool flag=false ;
        printf("Case #%d: ",tt++);
        for(i=1; i<=30; i++)
        {
            int len=dfs_len(i,A,B,L,R,K);
            if(K>len)
            {
                K-=len;
                continue ;
            }
            ret=1;
            dfs(i,A,B,L,R,K);
            flag=true ;

            printf("%d\n",ret);
            for(int j=i; j>0; j--)
                if(j==i) printf("%d",aa[j]);
                else printf(" %d",aa[j]);
            printf("\n");
            break;
        }
        if(!flag)
            printf("-1\n");


        /*bool ok = false;
        printf ("Case #%d: " , tt++);
        //枚舉長度
        for (int i = 1 ; i <= 30 ; i ++) {
            int cnt = dfs_len (i , A , B , L , R , K);
            if (K > cnt) {
                K -= cnt;
                continue;
            }
            ret = 1;
            dfs (i , A , B , L ,R , K);
            printf ("%d\n" , ret);
            for (int j = i ; j >= 1 ; j --) {
                printf ("%d%c" , aa[j] , j == 1 ? '\n' : ' ');
            }
            ok = true;
            break;
        }
        if (!ok) puts("-1");*/

    }
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章