先上一道例题:
POJ1840 Eqs
考虑具有以下形式的方程: a1x13 + a2x23 + a3x33 + a4x43 + a5x53 = 0
系数是从区间[-50,50]起的整数。 考虑解决方案(x1,x2,x3,x4,x5)来验证方程xi∈[-50,50],xi!=
0,任何i∈{1,2,3,4,5 }。确定满足给定方程的解数。 输入项 输入的唯一行包含由空格分隔的5个系数a1,a2,a3,a4,a5。 输出量
输出将在第一行包含给定方程的解数。
Sample Input37 29 41 43 47
Sample Output654
直观思路就是一个个枚举,时间复杂度是O(n^5)
实际上,我们可以把它变形成:
a1x13+a2x23+a3x23=-(a4x43+a5x53)
分两部分处理,一次处理左边哈希,一次枚举右边进行判断
因为同一个值出现有多种情况,所以还要储存次数:
Code:
#include<iostream>
using namespace std;
const unsigned long long MAXN=999999999;
const int p=133301;
int h[1000001],num[1000001],val[1000001],nxt[1000001],tot;
void Put(long long x){
int k=(x+MAXN)%p,flag=1,i;
for(i=h[k];i;i=nxt[i]){
if(val[i]==x){
flag=0;break;
}
}
if(flag){
nxt[++tot]=h[k];
num[tot]=1;
val[tot]=x;h[k]=tot;
}else num[i]++;//储存次数
}
int Find(int x){
int k=(x+MAXN)%p,flag=1,i;
for(i=h[k];i;i=nxt[i]){
if(val[i]==x){
flag=0;break;
}
}
if(flag) return 0;
else return num[i];
}
int a[5];
long long getx(long long x){
return x*x*x;
}
int ans;
int main(){
for(int i=0;i<5;i++) cin>>a[i];
for(int i=-50;i<=50;i++)
if(i!=0)
for(int j=-50;j<=50;j++)
if(j!=0)
for(int k=-50;k<=50;k++)
if(k!=0)
Put(a[0]*getx(i)+a[1]*getx(j)+a[2]*getx(k));//第一部分
for(int i=-50;i<=50;i++)
if(i!=0)
for(int j=-50;j<=50;j++){
if(j!=0)
ans+=Find(-(a[3]*getx(i)+a[4]*getx(j)));
}//第二部分
cout<<ans;
return 0;
}
时间复杂度是O(n3+n2)
然后是一道类似的:
POJ2785 4个总和为0的值
描述
SUM问题可以表示为:给定四个具有整数值的列表A,B,C,D,计算多少个四元组(a,b,c,d)∈A x B x C x D使得a + b
- c + d = 0。在下文中,我们假定所有列表的大小均相同。 输入项
输入文件的第一行包含列表n的大小(该值可以最大为4000)。然后,我们有n行包含四个分别属于A,B,C和D的整数值(绝对值最大为2 28)。
输出量对于每个输入文件,您的程序必须编写四倍数,其总和为零。 样本输入
6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46 26 -38 -10 62
-32 -54 -6 45 样本输出5
同样的思路,我们分两拨处理
Code:
#include<iostream>
using namespace std;
const unsigned long long MAXN=999999999;
const int p=4000*4000+7;//这里的素数很毒
int h[p+10],nxt[p+10],num[p+10],val[p+10],tot;
inline void add(int k,int x){
nxt[++tot]=h[k];
h[k]=tot;
val[tot]=x;
}
void put(int x){
int k=(x+MAXN)%p,flag=1,i;
for(i=h[k];i;i=nxt[i]){
if(val[i]==x){
flag=0;break;
}
}if(flag){
add(k,x);
i=tot;
}num[i]++;
}
int Find(int x){
int k=(x+MAXN)%p,flag=1,i;
for(i=h[k];i;i=nxt[i]){
if(val[i]==x){
flag=0;break;
}
}if(flag) return 0;
else return num[i];
}
int a1[4001],a2[4001],a3[4001],a4[4001],n;
int ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a1[i]>>a2[i]>>a3[i]>>a4[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) put(a1[i]+a2[j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) ans+=Find(-(a3[i]+a4[j]));
cout<<ans;
}
未完待续