基础训练赛第七场---26108--D题(数学,前缀和)


 题解思路:

        本题要求解决出直线经过范围内点个数最大个数,显然我们有(y-y0)=k(x-x0)两点式方程可以得出斜率k,所以只需要遍历每一个点和其他点的k,可以选择用map存贮不同的k值,每次遍历完成后将该循环内部的众数取出,做max比较,即 res = max(res, cnt);但我们要特判k不存在时候的数据记作cnt,之后还要res=max(res,cnt)才能退出一层循环,之后输出++res即可,++res是指将点数输出,因为我们求的是斜率不同值的次数,两个点确定一条斜率,所以最终结果要++!

        当然,本题如果倾斜角给出k就知道了,比如把题目改成经过倾斜角为45度的直线最多通过的点数有多少个,那么可以设y=kx+b;k已知,只需要枚举b,将b用map<int,int>mp存贮,输出mp.second最大值就可以了,很明显这个样子出题,题目难度会降低一个档次,思考维度少了,也不需要考虑k是否存在的情况!


 完整题解思路:

        考虑直线的点斜式y-y1=k(x-x1),枚举每个点作为固定点(x1,y1),再去枚举剩下的点(x,y),对于每一个(x,y)都可以求出一个对应的k。那么对于当前固定点(x1,y1)能构成的所有直线里,与之共线的点的最大个数就是k的众数出现的次数。

        令这个次数为,则最终的答案就是所有里面的最大值。

计算的方法与C题类似(就是y=kx+b的情况)

注意:

1.斜率不存在时需要特判

2.计算斜率会用到double,double虽然精度有限,但此题输入的坐标都是整数且都在[-1e9,1e9]的范围内,所以当斜率存在时,最大为2e9,没有超过double的有效位数16位。并且计算斜率只会用到一次除法运算,所以不会因为double精度(有效位数)不够而导致答案计算错误。

思考

若输入的坐标仍为整数,但范围是[-1e18,1e18],此时该如何处理?

本题代码如下:

            注释部分为一开始只进行一次for导致求出来的斜率均是和前一个比较的,没有和隔几个的比较;然后我第二次隔着比较出现了重复,应该是每次内层循环结束就要比较数量的大小!!!注意此时的map第一个key是double类型

#include<iostream>
#include<queue>
#include<set>
#include<string>
#include<numeric>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#define int long long
using namespace std;
const int MaxN = 2e5 + 5;
int ans = 0;
int n;
int a[200001];
int b[200001];

using pii = pair<int, int>;

struct jihe {
    int a;
    int b;
};
struct jihe arr[MaxN];
void solves() {
    cin >> n;
    map<double, int>mp;
    for (int i = 0; i < n; ++i)
    {
        cin >> arr[i].a >> arr[i].b;
    }
    int res = 0;
    for (int i = 0; i < n; i++) {
        map<double, int> mp;
        int cnt = 0;
        for (int j = 0; j < n; j++) {
            if (j == i) continue;
            double tmpx = arr[j].a - arr[i].a;
            double tmpy = arr[j].b - arr[i].b;
            double k;
            if (tmpx != 0) {
                k = 1.0 * tmpy / tmpx;
                mp[k]++;
            }
            else cnt++;
            res = max(res, cnt);
            res = max(res, mp[k]);
        }
    }
    cout << ++res << endl;
    /* for (int i = 0; i < n; ++i)
     {
         for (int j = i+1; j < n; ++j)
         {
             double tempx = arr[j].a - arr[i ].a;
             double tempy = arr[j].b - arr[i].b;
             if (tempx != 0)
             {
                 double k = 1.0 * tempy / tempx;
                 mp[k]++;
             }
             else cnt++;
         }

     }
     int ans = 0;
     for (auto& i : mp)ans = max(ans, i.second);
     ans = max(ans, cnt);
     cout << ans << endl;*/

}

signed  main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
        solves();
    return 0;
}

咱就是说this is--D题题源

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值