CF2074D Counting Points 题解

这个题注意到数据范围:\(\sum_{i=1}^n r_i = m\)\(1 \le n \le m \le 2\cdot 10^5\)
数据范围并不是很大,所以说可以考虑枚举。

但是存在一个问题,题目中的整点个数怎么求?
我们可以对圆的公式进行一下变换:
对于某个以\((x_i,0)\)为圆心,以\(r_i\)为半径的圆,其边界和内部的点必然满足:

\[(x-x_i)^2+y^2\leq r_i^2 \]

进行如下的转换:

\[y^2 \le r_i^2-(x-x_i)^2\iff-\sqrt{r_i^2-(x-x_i)^2} \le y \le \sqrt{r_i^2-(x-x_i)^2} \]

也就是说,对于一个圆内部的某个横坐标为\(x\)的点,它的\(y\)值一定在\(-\sqrt{r_i^2-(x-x_i)^2} \le y \le \sqrt{r_i^2-(x-x_i)^2}\)这个范围上,所以说这个横坐标为\(x\)的点在该圆及其内部的点共有\(2\left \lfloor {\sqrt{r_i^2-(x-x_i)^2}} \right \rfloor +1\)

现在还有一个问题,如果题目中的两两不相交那么就很容易计算出来了,但是,有多个圆相交了怎么办?只需要记录一下每个横坐标能取到的最大值就可以了。

记录最大值用std::map就可以了

总之,我们需要用map记录下每个圆内部的每个横坐标\(x\)对应的y的整数数量并取最大值,然后遍历一遍map即可
代码

#include <bits/stdc++.h>
using namespace std;
/*



*/
#define ll long long 
// #define double long double  
// #define double eps=1e-9;


void sol() {
    int n,m;
    cin>>n>>m;

    vector<ll> x(n),r(n);
    for(int i=0;i<n;i++) cin>>x[i];
    map<ll,ll> mp;
    for(int i=0;i<n;i++){
        cin>>r[i];
        for(int cur=x[i]-r[i];cur<=x[i]+r[i];cur++){
            mp[cur]=max(mp[cur],(ll)floor(sqrt(r[i]*r[i]-(cur-x[i])*(cur-x[i]))));
        }
    }
    ll ans=0;
    for(auto [key,val]:mp){
        ans+=(2*val+1);
    }
    cout<<ans<<'\n';
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t--) {
        sol();
    }
    return 0;
}

总结:数据范围不大可以考虑枚举,计算整点数量可以固定一维然后用另一维坐标下取整计算

posted @ 2026-03-01 15:46  1445141  阅读(17)  评论(0)    收藏  举报