2022.3.13

蓝书

AcWing 119. 袭击

思路:平面最近点对,多了个阵营的区别,但还是调了好久,有以下几点需要注意:1,题目数据范围太大如果分治的时候直接sort会超时,得用归并排序。2.因为是浮点数的判断所以得加eps。3.要特判一下当点的类型相同的时候为了不影响最小值的判断,让他们变成当前的最小值就可以。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 2e5 + 10;
const double INF = 1e10,eps=1e-6;
double mmin;
struct node
{
    double x, y;
    int id;
} point[N],tmp[N];
bool cmp(node a, node b) { return a.x < b.x; }
bool cmp2(node a, node b) { return a.y < b.y; }
double dist(node a,node b)
{
    if (a.id == b.id)
         return mmin;
    return (double)sqrt((double)(a.x - b.x) * (a.x - b.x) + (double)(a.y - b.y) * (a.y - b.y));
}
double solve(int l,int r)
{
    if(l>=r)
        return INF;
    int mid = l + r >> 1;
    double midx = point[mid].x;
    int midid = point[mid].id;
    double res = min(solve(l, mid), solve(mid + 1, r));
    int k = 0,i=l,j=mid+1;
    while(i<=mid&&j<=r)
    {
        if(point[i].y<point[j].y)
            tmp[k++] = point[i++];
        else
            tmp[k++]=point[j++];
    }
    while(i<=mid)
        tmp[k++] = point[i++];
    while(j<=r)
        tmp[k++] = point[j++];
    for (int i = l, j = 0; i <=r;i++,j++)
        point[i] = tmp[j];
    k = 0;
    for (int i = l; i <= r; i++)
    {
        // cout << midid << ' ' << point[i].id << '\n';
        if (point[i].x >= midx - res && point[i].x <= midx + res)
            tmp[k++] = point[i];
        }
    for (int i = 0; i < k; i++)
    {
        // cout << midid << ' ' << point[i].id << '\n';
        for (int j = i + 1; j < k && tmp[i].y - tmp[j].y+eps <= res; j++)
        {
            //if (tmp[i].id != tmp[j].id)
                // cout << dist(tmp[i], tmp[j]) << endl;
                res = min(res, dist(tmp[i], tmp[j]));
        }
        }
        mmin = min(mmin, res);
        return res;
}
int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n;i++)
        {
            scanf("%lf%lf", &point[i].x, &point[i].y);
            point[i].id = 1;
        }
        for (int i = n; i < n*2;i++)
        {
            scanf("%lf%lf", &point[i].x, &point[i].y);
            point[i].id = 2;
        }
        sort(point, point + 2 * n, cmp);
        mmin = dist(point[0], point[2 * n - 1]);
        printf("%.3lf\n",solve(0, 2 * n-1));
    }
    return 0;
}

AcWing 120. 防线

思路:因为防具都在成一排的并且每个位置可能多个防具,那如何找到防具为奇数个的位置,就需要利用到前缀和和二分,把二分和前缀和数组写完发现数据范围太大根本开不了,然后想了一会看了以前交的代码,忘记了一个等差数列性质,我们要求有多少个点也就是等差数列的长度除以公差,也就是一共有多少段,然后段数加1就是点的个数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
int n;
struct node
{
    ll s, e, d;
} a[N];
ll check(ll mid)
{
    ll ans = 0;
    for (int i = 1; i <= n;i++)
    {
        if(a[i].s<=mid)
        {
            ans += (min(a[i].e, mid) - a[i].s) / a[i].d + 1;
        }
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--)
    {
        cin >> n;
        ll l = 0, r = 0;
        for (int i = 1; i <= n;i++)
        {
            cin >> a[i].s >> a[i].e >> a[i].d;
            r = max(r, a[i].e);
        }
        while(l<r)
        {
            ll mid = l + r >> 1;
            if(check(mid)&1)
                r = mid;
            else
                l = mid + 1;
        }
        ll ans = check(r) - check(r - 1);
        if(ans&1)
        {
            cout <<r<<' '<< ans<<'\n';
        }
        else
            cout << "There's no weakness." << '\n';
    }

    return 0;
}

AcWing 121. 赶牛入圈

昨晚没写出来,今早看了题解,在处理二维前缀和的时候没处理好,因为草是在方格的中间而不是在点上,所以枚举的右下角的点还得-1。因为草的x,y可能很大,但实际上最多只有500单位的草,利离散化,二维前缀和处理草坐标,二分长度,定义k为二分到的长度大于mid的右下角的点,开始枚举以该点为右下角的矩阵的草的单位和。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1000+10,INF=1e8;
int a[N],b[N],uni[N],sum[N][N],c,n,m;
bool check(int mid)
{
    int k = lower_bound(uni + 1, uni + 1 + m, mid) - uni;
    k--;
    for (int x = k; x <= m;x++)
    {
        for (int y = k; y <= m;y++)
        {
            int x1 = upper_bound(uni + 1, uni + 1 + x, uni[x] - mid) - uni;
            int y1 = upper_bound(uni + 1, uni + 1 + y, uni[y] - mid) - uni;
            if(sum[x][y]-sum[x1-1][y]-sum[x][y1-1]+sum[x1-1][y1-1]>=c)
                return 1;
        }
    }
        return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int cnt=0;
    cin >> c >> n;
    for (int i = 1; i <= n;i++)
    {
        cin >> a[i] >> b[i];
        uni[++cnt] = a[i];
        uni[++cnt] = b[i];
    }
    sort(uni + 1, uni + 1 + cnt);
    m = unique(uni + 1, uni + 1 + cnt) - uni - 1;
    for (int i = 1; i <= n;i++)
    {
        int x = lower_bound(uni + 1, uni + 1 + m, a[i]) - uni;
        int y = lower_bound(uni + 1, uni + 1 + m, b[i]) - uni;
        sum[x][y]++;
    }
    for (int i = 1; i <= m;i++)
    {
        for (int j = 1; j <= m;j++)
            sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
    }
    int l=1,r=10000;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid))
		{
			r=mid;
		}
		else
		{
			l=mid+1;
		}
	}
    cout << r;
    return 0;
}
posted @ 2022-03-13 20:01  menitrust  阅读(31)  评论(0编辑  收藏  举报