Yukari's Birthday
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1373 Accepted Submission(s): 267
Problem Description
Today is Yukari's n-th birthday. Ran and Chen hold a celebration party for her. Now comes the most important part, birthday cake! But it's a big challenge for them to place n candles on the top of the cake. As Yukari has lived for such a long long time, though she herself insists that she is a 17-year-old girl.
To make the birthday cake look more beautiful, Ran and Chen decide to place them like r ≥ 1 concentric circles. They place k
i candles equidistantly on the i-th circle, where k ≥ 2, 1 ≤ i ≤ r. And it's optional to place at most one candle at the center of the cake. In case that there are a lot of different pairs of r and k satisfying these restrictions, they want to minimize r × k. If there is still a tie, minimize r.
Input
There are about 10,000 test cases. Process to the end of file.
Each test consists of only an integer 18 ≤ n ≤ 10
12.
Output
For each test case, output r and k.
Sample Input
Sample Output
题目大意:题目意思很好懂,只是数据范围很大。而且10000组数据动不动就TLE.反正昨天是没怎么想,六级过了,有点小激动。
解题思路:开始一直想的是枚举k,然后找到最接近的k+k^2+......+k^r=n或n-1.两边同时取对数,然后求得r最小是ln((n-1)*(k-1)+k)/ln(k)-1然后从这里开始枚举,如果>n就跳出来。这样是10^6的复杂度,但是10000组数据而且要用到取对数快速幂直接果断TLE了。然后r=2的时候先拿出来讨论,这样就变成了10^4的复杂度,但是最后还是由于用到了取对数TLE了。最后小吉吉直接果断把求幂打表,很牛叉的过了,此处应该有掌声。
昨天下来自己想了一下,r貌似最大才五六十的样子。写了一下发现2^40就超过了10^13觉得可以直接枚举r然后二分求k.不过从TLE,到WA,然后是除0爆栈,最终能AC不容易。这个题目今天一上午都在搞,真的是WA出翔了。这个题目借用了求幂打表的思想。具体思路见代码。
题目地址:Yukari's Birthday
AC代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
using namespace std;
__int64 n,i,j,l;
__int64 r,k,rk;
//__int64 res=pow(2,39);
//printf("%I64d\n",res);
//1099511627776
__int64 pow1[10002][65]; //对求幂打表
int main()
{
for(i=2;i<=10000;i++)
pow1[i][1]=i;
for(i=2;i<=10000;i++)
{
for(j=2;j<=40;j++)
{
pow1[i][j]=pow1[i][j-1]*i;
if(pow1[i][j]>1e17) //这个地方以免爆int64
pow1[i][j]=0;
}
}
while(~scanf("%I64d",&n))
{
r=1,k=n-1,rk=r*k; //r=1;
__int64 t1=sqrt((n-1)*1.0);
for(i=t1;i<=1000000;i++) //r=2;枚举k
{
__int64 tmp=i*i+i;
if(i>rk||tmp>n)
break;
if(tmp==n||tmp==n-1)
{
r=2,k=i,rk=r*k;
break;
}
}
for(j=3;j<=39;j++) //枚举r 二分K
{
int left=2; int right=10000;
int mid;
while(left<right)
{
mid=(left+right)>>1;
__int64 tmp;
if(pow1[mid][j+1]==0) //处理刚才爆int64的地方
{
right=mid-1;
continue;
}
tmp=(pow1[mid][j+1]-mid)/(mid-1);
if(tmp==n-1||tmp==n)
{
if(mid*j<rk||(mid*j==rk&&j<r))
r=j,k=mid,rk=r*k;
break;
}
if(tmp<n-1)
left=mid+1;
else
right=mid-1;
}
__int64 tmp;
mid=(left+right)>>1; //还要再检查一下mid,跳出来的情况没判断
tmp=(pow1[mid][j+1]-mid)/(mid-1);
if(tmp==n-1||tmp==n)
{
if(mid*j<rk||(mid*j==rk&&j<r))
{
r=j,k=mid,rk=r*k;
}
}
}
printf("%I64d %I64d\n",r,k);
}
return 0;
}
//78MS 5332K
第一次能排个名次,截个图