题意:给定一组整数数组,找出满足a*b=c的三元组的个数。
有点像leetcode 的three sum。数组排序后,如果x<y<z且三者都非零,一定有A[z]>A[x],A[z]>A[y],所以只要枚举x,y,在[y+1,N]的范围内寻找A[x]*A[y]是否存在即可。因为可能有多个相同值得A[z]存在,所以需要用lower_bound和upper_bound找出范围。lower_bound(target)返回第一个z0 such that A[z0]>=x,upper_bound(target)返回第一个z1 such that A[z1]>x。如果z0,z1都不存在,那么A[z]不存在。如果z0=z1,则不存在恰好等于target的数,否则,存在z1-z0个等于target的数。
另外要特殊处理的是存在0的情况,因为0*A[x]=0,如果A[x]>0,不再满足A[z]>A[x],A[z]>A[y],无法再用搜索解决。应为0和任意一个数相乘都是0,如果存在两个以上的0(e.g., n zeros),有C(n,2)*number of other positive integers个triple满足条件。
对于(0,0,0)这种case,之前的二分搜索已经可以包含了。
另一个坑是overflow,本来觉得overflow会出现负数,但实际不一定,而且test case还真有overflow后满足a*b=c但实际不满足的case。
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
//Kickstart Round G Problem A. Product Triplets
const int maxn=7010;
int T;
int N;
long long A[maxn];
long long ans;
long long compare()
{
long long ret=0;
for(int i=0;i<N;i++)
{
for(int j=i+1;j<N;j++)
{
for(int k=j+1;k<N;k++)
{
if(A[i]*A[j]==A[k]||A[i]*A[k]==A[j]||A[k]*A[j]==A[i])
{
cout<<A[i]<<" "<<A[j]<<" "<<A[k]<<endl;
ret++;
if(ret<0)
{
cout<<"error "<<ret<<endl;
}
}
}
}
}
return ret;
}
int main()
{
// int x0=2*1e5;
// long long x1=2*1e5;
// cout<<x0*x0<<" "<<x1*x1<<endl;
// long long x=65537;
// long long y=131073;
// cout<<x*x<<endl;
// return 0;
//use long long for A[i], otherwise, overflow, when overflow, a*b can still be positive, ahrd to find out
// freopen("input.txt","r",stdin);
freopen("A-large-practice.in","r",stdin);
freopen("A.txt","w",stdout);
clock_t START_TIME;
clock_t FINISH_TIME;
START_TIME=clock();
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
memset(A,0,sizeof(A));
ans=0;
cin>>N;
for(int i=0;i<N;i++)
{
cin>>A[i];
}
// printf("Case #%d: %d\n",ca,compare());
// continue;
sort(A,A+N);
for(int i=0;i<N;i++)
{
for(int j=i+1;j<N;j++)
{
// cout<<A[i]<<" and "<<A[j]<<endl;
long long goal=A[i]*A[j];
long long pos0=lower_bound(A+j+1,A+N,goal)-A;
long long pos1=upper_bound(A+j+1,A+N,goal)-A;
if(pos0==N)
{
continue;
}
else if(A[pos0]>goal)
{
// cout<<A[pos0]<<" "<<A[pos1]<<endl;
continue;
}
else
{
// cout<<A[pos0]<<" "<<A[pos1]<<" "<<pos0<<" "<<pos1<<endl;
ans+=pos1-pos0;
}
}
}
// deal with 0, as 0 * x=0, is not in increasing order
long long pos0=lower_bound(A,A+N,0)-A;
long long pos1=upper_bound(A,A+N,0)-A;
// cout<<pos0<<" "<<pos1<<endl;
if(pos0!=N&&pos1!=N&&A[pos0]==0)//0 exists and not all are 0
{
if(pos1-pos0>=2)//at least 2 zeros
{
long long tmp=(pos1-pos0)*(pos1-pos0-1)/2*(N-pos1);
ans+=tmp;
}
}
printf("Case #%d: %lld\n",ca,ans);
cerr<<"finish case "<<ca<<endl;
}
FINISH_TIME=clock();
cerr<<1.0*(FINISH_TIME-START_TIME)/CLOCKS_PER_SEC <<" (s) "<<endl;
return 0;
}