FZU-2125- 简单的等式

E - 简单的等式
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit

Status

Practice

FZU 2125
Description
如今有一个等式例如以下:x^2+s(x,m)x-n=0。

当中s(x,m)表示把x写成m进制时,每一个位数相加的和。如今。在给定n,m的情况下。求出满足等式的最小的正整数x。

假设不存在。请输出-1。
Input
有T组測试数据。下面有T(T<=100)行。每行代表一组測试数据。每一个測试数据有n(1<=n<=10^18),m(2<=m<=16)。


Output
输出T行,有1个数字。满足等式的最小的正整数x。

假设不存在,请输出-1。
Sample Input
4
4 10
110 10
15 2
432 13
Sample Output
-1
10
3
18

考数学,考一元二次方程的求解。
s(x,m)的区间[1,100]。仅仅是粗略的估算,但不影响做题。
s(x,m)最小值为1,这个一眼就能看出来。接下来求它的最大值。
我仅仅是粗略估算一下。2的100次方大于10的18次方。那2的100次方转换为二进制时各个位数相加的和肯定小于100,那我就取右边界为100.
为什么不转换为16进制?由于这样得到的返回值仅仅会更小。不信自己拿笔算。

思路:不要枚举x,枚举s(x,m)。最多一百次,怎么会超时
原方程变为x*x+s(x,m)*x-n=0;s(x,m)看成能够被枚举的已知数。那这就是关于x的一元二次方程了。经过配方开平方,能够得到
x=sqrt(n+(s(x,m)/2)*(s(x,m)/2))-s(x,m)/2;
通过配方得出x的值以后,带入s(x,m)。再带入原方程检验就可以。

代码

#include <iostream>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<string>
#include<string.h>
using namespace std;
int s(long long int x,long long int m)
{
    int sum=0;
    while(x)
    {
        sum+=x%m;
        x=x/m;
    }
    return sum;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long int n,m;
        scanf("%I64d%I64d",&n,&m);
        long long int num_x=-1;//初始化
        for(int i=1;i<100;i++)//i代表s(x,m)參数
        {
            long long int flag=sqrt(n*4+i*i)/2-i/2;//求根公式得到
            if(flag*flag+s(flag,m)*flag==n)//带入原方程检验
            {
                num_x=flag;
                break;
            }
        }
        printf("%I64d\n",num_x);
    }
}

注意数据类型

posted @ 2017-08-02 09:22  jzdwajue  阅读(129)  评论(0编辑  收藏  举报