计蒜客2019CSP膜你赛第一场

时间秒杀一切 提交于 2019-12-03 21:31:48

计蒜客2019CSP比赛第一场

巧妙避开这场比赛……

T1炮击

题目描述

\(rize\) 是一个可爱的女孩子。

一天,\(rize\) 进行了炮击的练习。炮击用的靶子为一个圆,其中有 \(n-1\) 个与靶子同心的圆,将靶子划分成了 \(n\) 个区域。这些区域里到外从 \(1\)\(n\) 编号,第 \(i\) 个区域的外径为 \(R_i\) 。每个区域有一个分数,第 \(i\) 个区域的分数为 \(s_i\)\(rize\) 发射了 \(m\) 枚炮弹。在靶平面上的以靶心为原点的直角坐标系下,第 \(i\) 枚炮弹击中的区域为一个半径为 \(r_i\)的圆,其圆心的坐标为 \((x_i, y_i)\) 。若一枚炮弹击中的区域与靶子中的某个区域存在交集,则发射这枚炮弹会得到这个区域的分数。这里的区域不包含边界。

\(rize\) 想知道发射每一枚炮弹的得分。

输入格式

第一行两个数 \(n, m\)
之后 \(n\) 行,每行两个整数 \(R_i, s_i\)
之后 \(m\) 行,每行三个整数 \(x_i, y_i, r_i\)

输出格式

\(m\)行,每行一个数表示答案。

数据范围

\(30\%\) 的数据 \(n, m \le 1000\)

另有 \(20\%\) 的数据 \(r_i = 1\)

另有 \(20\%\) 的数据 \(s_i = 1\)

对于 \(100\%\) 的数据,\(1 \le n, m \le 2 \times 10^5\)\(1 \le s_i \le 10^4\)\(-10^7 \le x_i, y_i \le 10^7\)\(1 \le r_i \le 10^7\)\(1 \le R_1 < R_2 < \cdots < R_n \le 10^7\)

“这是一道大水题”
我当时这么说的,但是直到最后我这个蒟蒻还是没写出来……

二分查找\(+\)前缀和

我们可以发现,对于每发炮弹,我们并不需要计算圆的大小,真正需要算的只有它的圆心和靶心的连线的距离分别加减它的半径:\(\sqrt{x^2 + y^2} + r\)是最远点,最近点需要特判,当\(\sqrt{x^2 + y^2} < r\)时最近点是圆心,否则是\(\sqrt{x^2 + y^2} - r\),然后考虑优化,就可以用前缀和,在考虑如何查找前缀和,就可以想到\(logn\)的二分查找……还挺绕

代码:

#include<bits/stdc++.h>
using namespace std;
#define rint register int
#define lb lower_bound
#define ub upper_bound 
int n, m;
int f[300010], c[300010];
inline int read( void ){
    int re = 0, f = 1;char ch = getchar();
    while( ch > '9' || ch < '0' ){
        if( ch == '-' ) f = -1;
        ch = getchar();
    }
    while( ch >= '0' && ch <= '9' ){
        re = re * 10 + ch - '0';
        ch = getchar();
    }
    return re * f;
}
int main( void ){
    n = read(); m = read();
    for( rint i = 1; i <= n; i++ ){
        c[i] = read(); 
        f[i] = read() + f[i - 1];
    }
    for( rint i = 1; i <= m; i++ ){
        double x, y;
        int r;
        x = read(); y = read(); r = read();
        double dis = sqrt( x * x + y * y );
        printf("%d\n",f[lb(c,c+n,(int)ceil(dis)+r)-c]-(dis<=r?0:f[ub(c+1,c+n+1, (int)dis-r)-c-1]));
    }
    return 0;
}

T2出行

还行,想出了正解,没想到处理方法

题目描述

\(syaro\) 是一个可爱的女孩子。

\(syaro\) 所在的城市有 \(n\)个街区,街区之间共有 \(m\) 条双向通行的道路,且任意两个街区可以通过这些道路互相到达。

一天,\(syaro\) 要带着无数只兔子从 \(1\) 号街区走到 \(n\) 号街区。由于 \(syaro\) 无法管理太多的兔子,于是她决定,如果她经过的道路中存在长度为 \(w\) 的道路,那么她出发时只会带不大于 \(w\) 只兔子。为了节省时间,她只会在总长度最短的若干条路径中选择一条走。

另外,有 \(k\) 个街区由于开了很多咖啡店,整个街区都弥漫着咖啡的气味。由于 \(syaro\) 闻到咖啡的气味就会迷失方向,因此她只会从不经过任何一个这样的街区的最短路径中选择一条走。如果所有最短路径都会经过这样的街区,她就会放弃出行。

\(syaro\) 告诉了 \(cocoa\) 自己的出行计划。 \(cocoa\) 作为一个擅长算术的女孩子,想知道 \(syaro\) 最多能带多少只兔子。当然,放弃出行意味着最多能带 \(0\) 只兔子。

输入格式
第一行三个数 \(n, m, k\)

第二行 \(k\)个数,表示开了很多咖啡店的街区编号;

之后$ m$ 行,每行三个数 \(u, v, w\),表示有一条从 \(u\)\(v\) 的长度为 \(w\) 的道路。

输出格式
输出一行一个数表示答案。

数据范围
对于 \(10\%\) 的数据 \(n, m \le 50\)\(m-n \le 10\)

对于 \(30\%\) 的数据 \(n, m \le 10^3\)

对于 \(60\%\)的数据 \(n, m \le 10^5\)

另有 \(20\%\)的数据 \(k = 0\)

对于 \(100\%\) 的数据 \(1 \le n, m \le 10^6\)
\(0 \le k \le n0≤k≤n,0 \le w \cdot n \le 10^9\)
。不保证没有重边,保证没有自环。

很明显这题是要把有咖啡店的点标记然后不向它们连边
然后在新图上找一下最短路里的最大边

当时不知道怎么想的,跑了个二分答案,二分边的长度,其实正确性有所保证,但是每次二分要跑一个\(O(nlogn)\)\(dij\)\(1e6\)跑一个\(O(nlogn)\)没有问题的,于是我理所应当的忽略了前面那个二分答案的\(O(logn)\),单单一个\(O(logn)\)不大,但是\(O(logn^2)\)就得考虑一下了,再加上计蒜客的评测姬跑得不快,导致我几乎没拿分

标答应该是\(dp\)

未完……

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!