hnust - 方程解的个数 - 枚举

题目描述

给定一个不超过10000的正整数n,问等式ac2+ad3+6abd=2bc2+2bd3+3a2d 有多少组不同的解?其中a,b,c,d均为整数且取值范围是区间[1,n]。若解(a1,b1,c1,d1)和解(a2,b2,c2,d2)相同,则有a1=a2,b1=b2,c1=c2,d1=d2.

输入

输入包含多组数据(不超过100组)。
每组数据一行,仅包含一个整数n。

输出

对于每一组数据的n,输出满足题意的方程解的数目。

样例输入

1
2

样例输出

0
5

来源

2016新生赛

题解

题意很明确,给定一个区间[1,n],问你该区间内有多少个不同的方程解。
显而易见d*d*d若取10000,就是10^12,所以long long存储数据。
这里写图片描述
这个题我TLE无数遍,要对数卡得无限精细才能AC,大家可以参考我怎么非规范卡时间的。

  • 首先都是对a-2b=0,有n/2*n*n个解,因为b最大可以取n/2种,c*d可以取n*n种。
  • 然后对c^2+d^3=3ad进行枚举。

    • 枚举方式一:对a,d枚举。
      当a枚举1-n个数时,可以限制d的枚举次数,d的最大极限是d=sqrt(3*a);
      通过ad可以推出,看c是否符合要求,即c<=n且c是正整数。符合要求则ans+=n;(这里n是b的个数为无限取)。但是如果a为偶数,就会出现重复的,所以要减去一种ans–;
    • 枚举方式二:对c,d枚举。对d分析,若a=n,c=0时,d取最大极限值,d^3=3ad,d^2<3n即d的最大范围为d=sqrt(3n);对c只能枚举1-n了^_^。第二种方法时间复杂度高一些!
    • 不管用方式一还是方式二,最后都要判断a是否为偶数,偶数的情况下就要减一种类,因为不能出现重复相同解。

代码

方式一代码

  • 内存:1724
  • 耗时:2744
  • 语言:C++/Edit
  • 代码长度:813 B
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
// (a-2b)(c^2-3ad+d^3)=0
int main()
{
  ll n, ans;
  while(~scanf("%lld",&n)){
    ll a, c, d;
    ans = n / 2;//有多少组a=2b的解
    ans *= n * n;//a=2b后,因为cd可以任意取1~n,
    for(a = 1; a <= n; a++)//对c^2-3ad+d^3=0的解枚举
    for(d = 1; d * d < 3 * a; d++){//限制d范围
        ll cc = 3 * a * d - d * d * d;
        c = sqrt(cc);
        //printf("%d %d %d\n",c,d,a);
        if(c>=1 && c <= n && cc==c*c){
            ans += n;
            if(a % 2 == 0)//a为偶数,即减去已算过的a=2b的数
                ans--;
        }
    }
    printf("%lld\n",ans);
  }
}

方式二代码

  • 内存:1724
  • 耗时:3896
  • 语言:C++/Edit
  • 代码长度:908 B
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
// (a-2b)(c^2-3ad+d^3)=0
int main()
{
  ll n, ans;
  while(~scanf("%lld",&n)){
    ll a, c, d;
    ans = n / 2;//有多少组a=2b的解
    ans *= n * n;//a=2b后,因为cd可以任意取1~n,
    ll maxd=sqrt(3*n+1);//3*d-d*d*d<=c*c
    for(d = 1; d<=maxd; d++)//限制d范围
        for(c = 1; c <= n; c++){//对c^2-3ad+d^3=0的解枚举
        a = d * d * d + c * c;
        if(a % (3 * d) == 0){
            a/=(3 * d);
            //printf("%d %d %d\n",c,d,a);
            if(a>=1 && a <= n){
                ans += n;
                if(a % 2 == 0)//a为偶数,即减去已算过的a=2b的数
                    ans--;
            }
        }
    }
    printf("%lld\n",ans);
  }
}

你可能感兴趣的:(C/C++,数学其他)