题目:
Description
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++; } } }