TOYS POJ - 2318 (二分+斜率)

本文深入探讨了TOYSPOJ-2318问题的解决策略,通过分析分割线斜率和二分查找,提出了两种有效的方法来计算矩阵区域内的点数。对比了cin与scanf输入效率,强调了在特定条件下scanf的性能优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题虫洞: TOYS POJ - 2318

 

黑洞内窥:

多组测试,一行六个数n, m, x1, y1, x2, y2;

锁定一个矩阵的左端点为(x1, y1),右下点为(x2, y2),

紧跟着n行,一行两个数a,b,代表(a, y1) 到 (b, y2)之间有一条直线。

n个点n条分割线将矩阵分成了n+1个区域。。。

再接着m个点的坐标(x,  y) ,最后输出每个区域的点数。

(注意:点不会落在斜线上,且一定在矩阵内)

 

思维光年:

其实容易想到的是,求出每条分割线的斜率,

然后用m个点的纵坐标y去求出每条分割线下对应的x,

由于分割线是从左到右给出的,

所以我们可以遍历一遍所以的分割线,如果 X > Xm

则该点就在该区域内,时间复杂度为O(n*m),

坑点:

我一开始是用全cin 读入,,,上面的复杂度O(n*m),我想也是,理所当然的残忍TLE,

然后我就二分分割线线斜率, 但还是TLE,这让我实在费解。。

最后我把所有的cin改成sacnf,,,,二分代码AC

暴力代码居然也。。。。绿了~~~~~我怀疑我被scanf绿了。。。

警告!警告!警告!:     请使用scanf! 请使用scanf!请使用scanf!

 

ACcode:(二分斜率)

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
#include      <map>
#include      <set>
#include   <vector>
#include    <queue>
#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
#include  <sstream>
using namespace std;
typedef long long int ll;
const ll MAXN = 5005;
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 100000007;
const double eps = 0.0000001;

pair<double, double>p[MAXN];
int n, m;
double x1, y1, x2, y2;
int num[MAXN];
double is[MAXN];
int main()
{
    while(cin >> n && n)
    {
        memset(num, 0, sizeof(num));
        memset(is, 0, sizeof(is));
        scanf("%d %lf %lf %lf %lf", &m, &x1, &y1, &x2, &y2);
        for(int i=0; i<n; ++i)
        {
            double a, b;
            scanf("%lf %lf", &a, &b);
            if(a == b)
                is[i] = a;
            else
            {
                p[i].first = (y1-y2)*1.0/(a-b);
                p[i].second = y1*1.0 - p[i].first*a;
            }
        }
        is[n] = x2;
        for(int i=0; i<m; ++i)
        {
            int x, y;
            scanf("%d %d", &x, &y);
            int l=0, r = n;
            while(l <= r)
            {
                int mid = (l+r)/2;
                double ans;
                if(is[mid])
                    ans = is[mid];
                else
                    ans = (y*1.0 - p[mid].second)/ p[mid].first;
                if(ans > x)
                    r = mid-1;
                else
                    l= mid+1;
            }
            num[l]++;
        }
        for(int i=0; i<=n; ++i)
            cout << i << ": " << num[i] << '\n';
        cout << '\n';
    }
    return 0;
}

 

ACcode:(改成scanf的暴力AC)

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
#include      <map>
#include      <set>
#include   <vector>
#include    <queue>
#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
#include  <sstream>
using namespace std;
typedef long long int ll;
const ll MAXN = 5005;
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 100000007;
const double eps = 0.0000001;

pair<double, double>p[MAXN];
int n, m;
double x1, y1, x2, y2;
int num[MAXN];
double is[MAXN];
int main()
{
    while(cin >> n && n)
    {
        memset(num, 0, sizeof(num));
        memset(is, 0, sizeof(is));
       scanf("%d %lf %lf %lf %lf", &m, &x1, &y1, &x2, &y2);
        for(int i=0; i<n; ++i)
        {
            double a, b;
            scanf("%lf %lf", &a, &b);
            if(a == b)
            {
                is[i] = a;
            }
            else
            {
                p[i].first = (y1-y2)*1.0/(a-b);
                p[i].second = y1*1.0 - p[i].first*a;
            }
        }
        is[n] = x2;
        for(int i=0; i<m; ++i)
        {
            double x, y;
           scanf("%lf %lf", &x, &y);
            for(int j=0; j<=n; ++j)    //暴力。。。
            {
                double ans;
                if(is[j])
                    ans = is[j];
                else
                    ans = (y*1.0 - p[j].second)/ p[j].first;
                if(ans >= x)
                {
                    num[j]++;
                    break;
                }
            }
        }
        for(int i=0; i<=n; ++i)
        {
            cout << i << ": " << num[i] << '\n';
        }
        cout << '\n';
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值