题目大意:给一个区间[A,B],表示有B - A + 1种火药,火药i的威力值为i,现在要用这些火药做炸弹,每次按原料的字典序做炸弹。每个炸弹的威力值是每种原料威力值的乘积。现在给一个区间[L,R]表示炸弹的威力值范围,求第K个炸弹的配方。
题目分析:因为炸弹的威力值是原料威力值的乘积,R不超过10^9,A至少为2,所以极端情况下炸弹至少要30种原料,所以直接搜就可以了。
首先根据给定的2个区间,求出重合的区间,表示只用一种原料能做的炸弹有多少,如果K满足这个范围,直接输出答案。
然后根据[L,R]区间确定所要原料的数量的上下界。然后枚举原料长度,dfs。
主要的剪枝是,当搜到第i中火药的时候,假设剩下的全部用威力值最大的B种火药,如果还不能达到炸弹威力值下界L,退出;假设剩下的全部用威力值最小的A种火药,已经超过炸弹威力值上界R,退出。
不过我加了这个剪枝还是TLE,后来又加了个小剪枝,就是搜到倒数第二层的时候,最后一层的情况直接统计,不用去搜最后一层了。
详情请见代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 ll;
ll A,B,L,R,K;
ll path[400];
bool flag;
ll pow(ll a,ll b)
{
ll ret = a;
for(int i = 1;i < b;i ++)
ret *= a;
return ret;
}
void dfs(ll cur,int deep,int dp,ll po)
{
if(flag)
return;
path[dp] = cur;
if(dp + 1 == deep)//倒数第二层
{
ll ta = L/po;
if(L%po)
ta ++;
ll tb = R/po;
ll tmp;
if(tb < cur)
tmp = 0;
else
{
if(tb <= B)
{
if(ta < cur)
tmp = tb - cur + 1;
else
tmp = tb - ta + 1;
}
else
{
if(ta < cur)
tmp = B - cur + 1;
else if(ta <= B)
tmp = B - ta + 1;
else
tmp = 0;
}
}
K -= tmp;
if(K > 0)
return;
else
K += tmp;
}
ll i;
if(dp == deep)
{
if(po >= L && po <= R)
K --;
if(K == 0)
{
printf("%I64d\n",po);
for(i = 1;i < dp;i ++)
printf("%I64d ",path[i]);
printf("%I64d\n",path[i]);
flag = true;
}
return;
}
i = L/po;
i = i / (pow(B,(deep - dp - 1)));
if(i < cur)
i = cur;
for(;i <= B;i ++)
{
if(pow(i,(deep - dp)) * po > R)
return;
dfs(i,deep,dp + 1,po * i);
}
}
int main()
{
int t,cas = 0;
ll i,j;
scanf("%d",&t);
while(t --)
{
scanf("%I64d%I64d%I64d%I64d%I64d",&A,&B,&L,&R,&K);
printf("Case #%d: ",++cas);
int cros = 0;
if(R < A)
{
printf("-1\n");
continue;
}
ll tans;
if(R <= B)
{
if(L < A)
{
cros = R - A + 1;
if(cros >= K)
tans = A + K - 1;
}
else
{
cros = R - L + 1;
if(cros >= K)
tans = L + K - 1;
}
}
else
{
if(L < A)
{
cros = B - A + 1;
if(cros >= K)
tans = A + K - 1;
}
else if(L >= A && L <= B)
{
cros = B - L + 1;
if(cros >= K)
tans = L + K - 1;
}
else
cros = 0;
}
if(cros >= K)
{
printf("%I64d\n%I64d\n",tans,tans);
continue;
}
K -= cros;
ll l,r;
l = r = 2;
ll ta,tb;
ta = A;
tb = B;
while((ta*A) < R)
{
r ++;
ta = ta * A;
}
while((B*tb) < L)
{
l ++;
tb = tb * B;
}
flag = false;
for(i = l;i <= r && !flag;i ++)
{
j = L / (pow(B,i - 1));
if(j < A)
j = A;
for(;j <= B && !flag;j ++)
{
if(pow(j,i) > R)
break;
dfs(j,i,1,j);
}
}
if(!flag)
printf("-1\n");
}
return 0;
}
/*
100
2 2 1 4 1
2 5 1 4 4
73 23642 12 20903 29401
2 50 1 1000000000 815180
2 1000000 2 1000000000 1000000
2 100000 2 1000000000 1000000
2 10000 2 1000000000 1000000
2 1000 2 1000000000 1000000
2 100 2 1000000000 1000000
2 100000 1000000 1000000000 1000000
*/
/*
ans:
2
2
4
2 2
-1
59200
4 4 5 20 37
4
2 2
616
11 56
510151
101 5051
27
3 3 3
679728
7 17 68 84
3046246
31 98266
*/