kAri OJ130 非平方等式(二分加枚舉)

時間限制 1000 ms 內存限制 262144 KB

題目描述

考慮等式:

x2 + s(xx - n = 0, 

其中x,n是正整數,s(x)是個函數,其值等於x在十進制下所有數字的和。

現給出整數n的大小,請你求出最小的滿足條件的正整數x。

輸入格式

輸入僅包含一個整數n (1 ≤ n ≤ 1018) .

輸出格式

如果不存在這樣的x,請輸出-1;否則請輸出滿足條件的最小的整數x (x > 0)

輸入樣例

2

輸出樣例

1


解題思路:

1)如果採取從1到sqrt(n)枚舉的話,複雜度是O(10^9),肯定會超時。

2)容易想到把範圍縮小再枚舉,於是嘗試從sqrt(n)-1000000到sqrt(n)枚舉,不過WA掉了。

於是開始想到更換思路。

x*x+S(x)*x隨着x是近似單調遞增的。可以試着二分。

不過,把1-1000的x*x+S(x)*x函數值打印出來。會發現不是嚴格單調遞增。




可以先根據二分確定大致範圍,然後這個範圍內枚舉。

(直接枚舉會超時,直接二分會WA掉。)

PS:由於n最大是10^18,所以要用long long.


AC代碼:
#include<iostream>
#include<cmath>
using namespace std;

long long getval(long long tmp)
{
    long long ans=0;
    long long t=tmp;
    while(tmp)
    {
        ans+=tmp%10;
        tmp/=10;
    }

    ans=ans*t+t*t;
    return ans;
}

int main()
{

    /*for(long long i=1;i<=1000;i++)
    {
    	cout<<getval(i)<<" ";
    	if(i%10==0) cout<<endl;
    }*/

    long long n;
    while(cin>>n)
    {
        long long l=1;
        long long r=sqrt(n);
        long long mid;

        int flag=0;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(getval(mid)==n)
            {
                break;
            }
            if(getval(mid)<n)
                l=mid+1;
            else
                r=mid-1;
        }

        long long mi=mid-100000;
        if(mi<1) mi=1;
        long long ma=mid+100000;
        if(ma>sqrt(n))  ma=sqrt(n);
        for(long long i=mi; i<=ma; i++)
        {
            if(getval(i)==n)
            {
                flag=1;
                cout<<i<<endl;
                break;
            }
        }

        if(!flag)
            cout<<"-1"<<endl;
    }
    return 0;
}




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