zoukankan      html  css  js  c++  java
  • GHOJ 234 飞镖

    题目描述

            小明喜欢玩飞镖游戏,他会把每次的得分都记录在数组中。今天有个飞镖大奖,得奖的规则是:如果你4次飞镖的得分先后是(a,b,c,d),满足a×b×c=d。

            小明准备把记录里的其他项删除,只留下满足获奖条件的4个分数,他想问你有多少种不同方案?

     

    输入输出格式

    输入格式

            第一行,一个整数N。(N <= 2000)

            第二行,N个整数,每个整数范围在[1...10^6]。

     

    输出格式

            一行,一个整数,代表方案数。

     

    输入输出样例

    输入样例一

    6

    10 2 2 7 40 160

     

    输出样例一

    2

    输入样例二

    8

    128 64 32 16 8 4 2 1

    输出样例二

    0

    题解

            暴力枚举a,b,c,求d是否存在,可以做到O(n³)的时间复杂度,但是显然并不能满足这题的数据范围。

            我们可以从另一个角度出发。由题的a*b=d/c,我们可以先枚举a*b,记录b出现的位置,然后枚举d/c,根据c的位置来找满足b的位置符合题意的情况数,这样看起来也是O(n³),但实际上用二分查找优化可以做到O(n²logn),刚好可以通过这题。

    #include <iostream>
    #include <vector>
    
    #define MAX_N 2000
    #define PTS 1000000
    
    using namespace std;
    
    int n;
    int a[MAX_N | 1];
    vector<int> c[PTS | 1];
    long long ans;
    
    inline int BS(int x, int p)
    {
        int len = c[x].size();
        int lt = 0, rt = len - 1, mid;
        while(lt <= rt)
        {
            mid = lt + rt >> 1;
            if(c[x][mid] >= p) rt = mid - 1;
            else if(mid + 1 < len && c[x][mid + 1] < p) lt = mid + 1;
            else return mid + 1;
        }
        return 0;
    }
    
    int main()
    {
        cin >> n;
        for(register int i = 1; i <= n; ++i)
        {
            cin >> a[i];
        }
        for(register int i = 2; i + 2 <= n; ++i)
        {
            for(register int j = 1; j < i; ++j)
            {
                if((long long)a[i] * a[j] > PTS) continue;
                c[a[i] * a[j]].push_back(i);
            }
        }
        for(register int i = 3; i < n; ++i)
        {
            for(register int j = i + 1; j <= n; ++j)
            {
                if(a[j] % a[i]) continue;
                ans += BS(a[j] / a[i], i);
                // cout << i << " " << j << " " << ans << endl;
            }
        }
        cout << ans;
        return 0;
    }
    参考程序O(n²logn)版

            然而,当数据范围再放大一些的时候,上面的做法就不行了。我们可以看看上面的做法的缺点,在于需要查找b的位置,如果我们可以在枚举d/c的时候同时枚举a*b,就可以做到O(n²)的时间复杂度,而这真的可以实现,只需要利用b的位置在c的位置前面这个特性即可,具体可以参考下面的程序。(而且这个做法还更好写。。)

    #include <iostream>
    
    #define MAX_N 2000
    #define PTS 1000000
    
    using namespace std;
    
    int n;
    int a[MAX_N | 1];
    int c[PTS | 1];
    long long ans;
    
    int main()
    {
        cin >> n;
        for(register int i = 1; i <= n; ++i)
        {
            cin >> a[i];
        }
        for(register int i = 3; i < n; ++i)
        {
            for(register int j = 1; j < i - 1; ++j)
            {
                if((long long)a[i - 1] * a[j] > PTS) continue;
                ++c[a[i - 1] * a[j]];
            }
            for(register int j = i + 1; j <= n; ++j)
            {
                if(a[j] % a[i]) continue;
                ans += c[a[j] / a[i]];
            }
        }
        cout << ans;
        return 0;
    }
    参考程序O(n²)版
  • 相关阅读:
    成员变量和局部变量
    成员变量和局部变量
    对象和类
    数组
    Scanner--控制台输入
    Java运算符
    Java数据类型
    TextView控件
    Android控件
    注释
  • 原文地址:https://www.cnblogs.com/kcn999/p/10353584.html
Copyright © 2011-2022 走看看