2020牛客寒假算法基础集训营1

2020牛客寒假算法基础集训营1

C umi和弓道

链接:https://ac.nowcoder.com/acm/contest/3002/C
来源:牛客网

umi对弓道非常痴迷。
有一天,她在研究一个射箭问题:
在一个无限大的平面中,她站在 ( x 0 , y 0 ) (x_0,y_0) (x0,y0) 这个坐标。
n n n个靶子,第 i i i 个靶子的坐标是
umi准备在 x x x轴或 y y y 轴上放置一块挡板来挡住弓箭的轨迹,使得她可以射中的靶子数量不超过 k k k 个。
她想知道挡板的最短长度是多少?
注:假定弓箭的轨迹是起点为umi坐标、长度无穷大的射线。umi和靶子的体积可以无视。挡板的边缘碰到弓箭轨迹也可视为挡住弓箭。
注2:挡板不能弯折,起始和终点必须在同一坐标轴上。

题解

不要想难,根据题意即可知,板子要么在x轴上,要么在y轴上
就求x轴的交点,然后算能否有长度 l l l的板子符合题意
y y y轴的交点,然后算是否有长度 l l l的板子符合题意

#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
const double pi = acos(-1.0);
const double eps = 1e-12;
typedef long long ll;
const int MAXN = 1e5 + 10;
 
typedef struct point vec;
struct point { //点的基本数据结构
    double x, y;
    double poe;
    int pos;
    point(double _x = 0, double _y = 0)
        : x(_x)
        , y(_y)
    {
    }
    double len() //模长
    {
        return sqrt(x * x + y * y);
    }
    vec chuizhi()
    {
        return vec(-y, x);
    }
    double operator*(const point& i_T) const //点积
    {
        return x * i_T.x + y * i_T.y;
    }
    double operator^(const point& i_T) const //叉积
    {
        return x * i_T.y - y * i_T.x;
    }
    point operator*(double u) const
    {
        return point(x * u, y * u);
    }
    bool operator==(const point& i_T) const
    {
        return fabs(x - i_T.x) < eps && fabs(y - i_T.y) < eps;
    }
    point operator/(double u) const
    {
        return point(x / u, y / u);
    }
    point operator+(const point& i_T)
    {
        return point(x + i_T.x, y + i_T.y);
    }
    point operator-(const point& i_T)
    {
        return point(x - i_T.x, y - i_T.y);
    }
    friend bool operator<(point a, point b)
    {
        return fabs(a.y - b.y) < eps ? a.x < b.x : a.y < b.y;
    }
    void atn2()
    {
        poe = atan2(y, x);
    }
    friend ostream& operator<<(ostream& out, point& a)
    {
        //cout << a.x << ' ' << a.y;
        printf("%.8f %.8f", a.x, a.y);
        return out;
    }
    friend istream& operator>>(istream& in, point& a)
    {
        scanf("%lf%lf", &a.x, &a.y);
        return in;
    }
};
point p[MAXN];
int n;
vector<double> xx, yy;
int bijiao(double x, double y)
{
    if (fabs(x - y) < eps)
        return 0;
    if (x > y)
        return 1;
    return -1;
}
double INF = 1e30;
int main()
{
    int k;
    cin >> p[0];
    cin >> n >> k;
    int m = n - k;
    for (int i = 1; i <= n; i++)
        cin >> p[i];
    for (int i = 1; i <= n; i++) {
        if (p[i].x * p[0].x > 0)
            yy.push_back(INF);
        else
            yy.push_back(p[i].y - p[i].x * (p[0].y - p[i].y) / (p[0].x - p[i].x));
    }
    for (int i = 1; i <= n; i++) {
        if (p[i].y * p[0].y > 0)
            xx.push_back(INF);
        else
            xx.push_back(p[i].x - (p[i].y * (p[0].x - p[i].x) / (p[0].y - p[i].y)));
    }
    sort(xx.begin(), xx.end());
    sort(yy.begin(), yy.end());
    double minn = INF;
    for (int i = 0; i + m - 1 < xx.size(); i++) {
        if (bijiao(xx[i], INF) == 0)
            break;
        minn = min(minn, xx[i + m - 1] - xx[i]);
    }
    for (int i = 0; i + m - 1 < yy.size(); i++) {
        if (bijiao(yy[i], INF) == 0)
            break;
        minn = min(minn, yy[i + m - 1] - yy[i]);
    }
    if (bijiao(minn, INF) == 0)
        cout << -1 << endl;
    else
        printf("%.7f\n", minn);
    return 0;
}

F maki和tree

链接:https://ac.nowcoder.com/acm/contest/3002/F
来源:牛客网

有一天,maki拿到了一颗树。所谓树,即没有自环、重边和回路的无向连通图。
这个树有 n n n个顶点, n − 1 n-1 n1 条边。每个顶点被染成了白色或者黑色。
maki想知道,取两个不同的点,它们的简单路径上有且仅有一个黑色点的取法有多少?
注:
①树上两点简单路径指连接两点的最短路。
1在这里插入图片描述 的取法视为同一种。

题解

对于一个黑色的点,其对应的路径取法,是与它相连的白色点联通块 f [ i ] f[i] f[i]有关的
∑ 1 k ∑ i k f [ i ] ∗ f [ j ] + ∑ 1 k f [ i ] \sum_{1}^{k}\sum_{i}^{k}f[i]*f[j]+\sum_{1}^{k}f[i] 1kikf[i]f[j]+1kf[i]
然后求相连的联通块大小,用dfs也行,并查集也行

#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
const double pi = acos(-1.0);
const double eps = 1e-8;
typedef long long ll;
const ll INF = LLONG_MAX;
const ll ENF = LLONG_MIN;
const int MAXN = 1e6 + 10;
const int inf = __INT_MAX__;
const int enf = INT_MIN;

char s[MAXN];
vector<int> e[MAXN];
int f[MAXN], si[MAXN];
int fa(int x)
{
    return f[x] = (x == f[x] ? x : fa(f[x]));
}
vector<int> v;
int main()
{
    int n;
    cin >> n;
    cin >> (s + 1);
    for (int i = 1; i <= n; i++) {
        if (s[i] == 'B') {
            v.push_back(i);
            continue;
        }
        f[i] = i;
        si[i] = 1;
    }
    for (int i = 1; i < n; i++) {
        int x, y;
        cin >> x >> y;
        if (s[x] == 'B' && s[y] == 'B')
            continue;
        e[x].push_back(y);
        e[y].push_back(x);
        if (s[x] == 'B' || s[y] == 'B')
            continue;
        int fx = fa(x), fy = fa(y);
        if (fx == fy)
            continue;
        f[fy] = fx;
        si[fx] += si[fy];
    }
    ll sum = 0;
    for (auto it : v) {
        vector<int> a;
        for (auto jt : e[it])
            a.push_back(si[fa(jt)]);

        int num = a.size();
        for (int i = 0; i < num; i++) {
            sum += a[i];
            for (int j = i + 1; j < num; j++)
                sum += a[i] * a[j];
        }
    }
    cout << sum << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值