蓝桥杯小白入门赛第四期 第三道题目 统计二元组的个数 有坑点

90 阅读2分钟

我刚开始是这样写的:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N];

int main()
{
  int n;cin>>n;
  int ans=0;
  for(int i=1;i<=n;i++)cin>>a[i];
  


   for(int i=1;i<=n;i++){
     for(int j=i+1;j<=n;j++){
       if(a[i]/j==a[j]/i){
         ans++;
       }
     }
   }cout<<ans<<"\n";

  return 0;
}

答案错了: image.png Debug

通过监视我们发现: 当a[i]j=43=1.3\frac{a[i]}{j}= \frac{4}{3}=1.3 ,a[j]i=32=1.5\frac{a[j]}{i}= \frac{3}{2}=1.5的时候,编译器进行了向下取整,使得它们的值都为1 1,因此计数器++; image.png

image.png

为了消除除法带来的精度问题我们将其转换为乘法,即ab=cd \frac{a}{b}=\frac{c}{d}可以转换为a×d=c×ba \times d =c \times b ,修改完代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N];

int main()
{
  int n;cin>>n;
  int ans=0;
  for(int i=1;i<=n;i++)cin>>a[i];
  


   for(int i=1;i<=n;i++){
     for(int j=i+1;j<=n;j++){
       if(a[i]*i==a[j]*j){
         ans++;
       }
     }
   }cout<<ans<<"\n";

  return 0;
}

运行结果正确,但是运行时长跑了4秒多:

因为数据范围是1e5,而我们写了两层循环。 image.png

为了提高效率,只能用一个for循环:

我们用一个map统计 a[i]×ia[i] \times i的出现次数,

最后map里面存储的就是所有二元组的个数,最后我们可以使用高斯求和公式nn12 \frac{n*(n-1)}{2}求出map里面存放的所有二元组的个数,代码如下:

注意,这个用法是c++17的用法,所以需要升级一下编译器环境。

#include <iostream>
#include<map>
using namespace std;
const int N = 1e5 + 9;
int a[N];
map<int, int>mapp;
int main()
{
    int n; cin >> n;
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];

    }
    for (int i = 1; i <= n; i++)
    {
        mapp[a[i] * i]++;

    }

    for (auto& [x, y] : mapp)
    {
        ans += y * (y - 1) / 2;
    }
    cout << ans << "\n";

    return 0;
}

或者不想用c++17的语法也可以这样:

    for (auto& it : mapp)
    {
        int y=it.second;
        ans += y * (y - 1) / 2;
    }
    cout << ans << "\n";

但是这个代码提交之后通过不了: image.png

原因是每个数据都是1e5,一共有1e5个数据,假设i=1e5,a[i]=1e5。那么a[i]×ia[i]×i 就会爆int。 因此我们需要开longlong,开完之后就可以过了: image.png