题目:
Description
a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0
The coefficients are given integers from the interval [-50,50].
It is consider a solution a system (x1, x2, x3, x4, x5) that verifies the equation, xi∈[-50,50], xi != 0, any i∈{1,2,3,4,5}.
Determine how many solutions satisfy the given equation.
Input
Output
Sample Input
37 29 41 43 47
Sample Output
654
本题直接想到的是“暴力破解法”直接枚举。但是用于方程原型复杂度较高,N^5,N的规模为100,直接算的话要计算100^5次方程,肯定会超时。
所以要将方程做一个变形,变为:
-(a1x13+ a2x23)==a3x33+ a4x43+ a5x53。
现在可以暴力破解了,分别把两边的所有取值存入数组(由于本题只要求对解进计数,所以一维就足够了),再作比较。
作暴力破解时,可以把Xi看做互相独立的。所以可以在一个三层的循环中进行,即外面两层循环用来枚举方程左边的值,最里层枚举方程右边的值。
(这样复杂度就变成了N^3.)
破解出方程两边的所有取值之后,接下来就是匹配解了。
有两种策略,一是,由左边的值匹配右边的;另一是,由右边的值匹配左边的。由于需要对被匹配的一边的值序列进行排序,而考虑到整个过程的效率,必须尽可能的使被排序的序列较长(此时效率更高)。所以,左配右的策略更好。
排序,可以用 STL 的 sort ,或者C语言的 qsort;(sort的复杂度是O(NlogN),qsort的最佳效率为O(NlogN))
匹配过程是:对于任意一个左边的取值,如果右边的值集合里有 n 个和它相同的值,则解数目加 n ,所以可以使用 STL 的for_each(),只须自己再完成一个函数,这个函数实现对任意 的一个值,找出它在右边(集合)出现几次。
用STL可以完美的实现。看看AC的源码,就知道STL有多么好用。
#include <cstdio>
#include <algorithm>
using namespace std;
#define cub(x) (x*x*x)
int alist[10000], blist[1000000];
int *aend=alist, *bend=blist;
int rescnt=0;
// void printi(int n) { printf("%d\n", n); }
void findroot( int an );
int main()
{
// freopen("aaa.txt","r",stdin);
int a[5];
for (int i=0; i<5; i++) scanf("%d", a+i);
for (int i=-50; i<=50; i++) if(i)
for (int j=-50; j<=50; j++) if(j)
{
*(aend++) = -(a[0]*cub(i) + a[1]*cub(j) );
for (int k=-50; k<=50; k++) if(k){
*(bend++) = a[2]*cub(i) + a[3]*cub(j) + a[4]*cub(k);
}
}
// sort(alist, aend);
sort(blist, bend);
// for_each(alist, aend, printi );
// for_each(blist, bend, printi );
for_each( alist, aend, findroot );
printf("%d\n", rescnt);
return 0;
}
void findroot(int an)
{
int* ipl = lower_bound(blist, bend, an);
if (ipl != bend ) {
for( ; ; ipl++){
if ( *ipl > an ) return;
rescnt++;
}
}
}