Bombs
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 12 Accepted Submission(s) : 2
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).
迷迷糊糊的開始搜索練習,這個是一開始看的題目。
看到的第一個想法,直接暴力搜索,超時!
參考了大神的博客 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");*/
}
}