Problem A. Product Triplets Google Kickstart Round G 2018

题意:给定一组整数数组,找出满足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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值