原链接:
点我QωQ
题意简述
多组数据,每次给定 a , b , c , d a,b,c,d a,b,c,d,求有多少 x 1 , x 2 , x 3 , x 4 x1,x2,x3,x4 x1,x2,x3,x4满足 a x 1 2 + b x 2 2 + c x 3 2 + d x 4 2 = 0 ax1^2+bx2^2+cx3^2+dx4^2=0 ax12+bx22+cx32+dx42=0。保证 a , b , c , d a,b,c,d a,b,c,d在 [ − 50 , 50 ] [-50,50] [−50,50]范围内,求的 x 1 , x 2 , x 3 , x 4 x1,x2,x3,x4 x1,x2,x3,x4要在 [ − 100 , 100 ] [-100,100] [−100,100]的计数。
数据
输入
多组数据,读入到文件尾。每组数据包含四个正整数 a , b , c , d a,b,c,d a,b,c,d,在 [ − 50 , 50 ] [-50,50] [−50,50]范围内。(即 > = − 50 , < = 50 >=-50,<=50 >=−50,<=50)。
输出
有多少 x 1 , x 2 , x 3 , x 4 x1,x2,x3,x4 x1,x2,x3,x4满足条件并且 − 100 < = x 1 , x 2 , x 3 , x 4 < = 100 -100<=x1,x2,x3,x4<=100 −100<=x1,x2,x3,x4<=100。
样例
输入
1 2 3 -4
1 1 1 1
输出
39088
0
思路
显然四层循环是过不去的。。。经过实践,三层也是过不去的。。。必须要
O
(
10
0
2
)
O(100^2)
O(1002)
才能过,带
l
o
g
log
log都不行。。。
但是我们要先能把四层循环写出来。代码:
int ans=0;
for(int x1=-100;x1<=100;++x1)
{
for(int x2=-100;x2<=100;++x2)
{
for(int x3=-100;x3<=100;++x3)
{
for(int x4=-100;x4<=100;++x4)
{
if (x1*x1*a+x2*x2*b+x3*x3*c+x4*x4*d==0)
{
++ans;
}
}
}
}
}
我们对这个代码作一些变形:
int ans=0;
for(int x1=-100;x1<=100;++x1)
{
for(int x2=-100;x2<=100;++x2)
{
for(int x3=-100;x3<=100;++x3)
{
for(int x4=-100;x4<=100;++x4)
{
if (x3*x3*c+x4*x4*d==-(x1*x1*a+x2*x2*b))
{
++ans;
}
}
}
}
}
你会发现我只是移项了一下。。。
但是这样之后就能想出一个优化了。我们会发现,后面两层循环相当于求有多少
x
3
,
x
4
x3,x4
x3,x4满足
c
x
3
2
+
d
x
4
2
=
−
(
a
x
1
2
+
b
x
2
2
)
cx3^2+dx4^2=-(ax1^2+bx2^2)
cx32+dx42=−(ax12+bx22)。然后这个东西我们珂以用一个
m
a
p
map
map记录出来。我们会轻易想到用
S
T
L
STL
STL的
m
a
p
map
map做。但是我没这么做,因为经过计算,会
T
L
E
。
。
。
TLE。。。
TLE。。。(不是带一个特别大的
l
o
g
log
log么。。。)
想想优化。 S T L STL STL的 m a p map map带一个 l o g log log,但是我们其实并不需要带 l o g log log。我们能求出来的最小值是 10 0 2 × − 50 100^2\times -50 1002×−50,即 − 5 × 1 0 5 -5\times10^5 −5×105。我们只要开一个长度为 2 × 1 0 6 2\times 10^6 2×106的数组,整个往右滚动 1 0 6 10^6 106位,就都珂以变成正下标了,直接上数组。在清空的时候,也不要直接 m e m s e t memset memset,而是反向进行计算的操作( + + +变 − - −),这样就珂以保证任何计算都是 O ( 10 0 2 ) O(100^2) O(1002)的了,也就珂以过了。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
#define int long long
#define N 1001000
struct Map//更快的Map(不带log)
{
int v[(N<<1)+100];
void clear()
{
memset(v,0,sizeof(v));
}
int& operator[](int i)//重载[]运算符
{
return *(v+i+N);
//取值的时候向右滚动
}
};
Map rec2;
//rec2[i]表示x3*x3*c+x4*x4*d==i的有多少
int a,b;
int c,d;
void Build()
{
for(int i=-100;i<=100;++i)
{
for(int j=-100;j<=100;++j)
{
if (i and j)//都不能是0
{
++rec2[i*i*c+j*j*d];
}
}
}
}
void Solve()
{
int ans=0;
for(int i=-100;i<=100;++i)
{
for(int j=-100;j<=100;++j)
{
if (i and j)
{
ans+=rec2[-(i*i*a+j*j*b)];
//记录答案
}
}
}
printf("%lld\n",ans);
}
void Clear()
{
for(int i=-100;i<=100;++i)
{
for(int j=-100;j<=100;++j)
{
if (i and j)
{
rec2[i*i*c+j*j*d]--;
//清空
}
}
}
}
void Main()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
while(scanf("%lld%lld%lld%lld",&a,&b,&c,&d)==4)
{
Build();
Solve();
Clear();
}
}
#undef int //long long
};
int main()
{
Flandle_Scarlet::Main();
return 0;
}
本文介绍了一种高效解决四元二次方程问题的方法,通过优化算法将复杂度从四层循环降低至O(100^2),利用自定义Map结构避免log开销,实现快速求解。
852

被折叠的 条评论
为什么被折叠?



