AtCoder Beginner Contest 259 A-E

AtCoder Beginner Contest 259

https://atcoder.jp/contests/abc259

A - Growth Record

按照题意模拟:

#include <bits/stdc++.h>

using namespace std;

int main () {
    int n, m, x, t, d;
    cin >> n >> m >> x >> t >> d;
    if (m >= x) cout << t;
    else    cout << t - (x-m)*d;
}

B - Counterclockwise Rotation

题意

给一点坐标\((a,b)\)和旋转角度\(d\),求旋转后的坐标

解法

看了题解学到两个新的函数:

  1. hypot(): hypot(x,y)=\(\sqrt{x^2+y^2}\)(可传2-3个参数)
  2. atan2(): atan2(x,y)=\(arctan\frac yx\),返回夹角,范围为\([-\pi,\pi]\)可区分象限 (有了这个函数就不用分类讨论象限了)

别忘了将\(\theta\)转为弧度制:\(\frac{d\times \pi}{180}\)
最后化为极坐标即可。

Code

#include <bits/stdc++.h>
#define pi acos(-1)

using namespace std;

int main () {
    int a, b, d;
    cin >> a >> b >> d;
    
    double r = hypot (a, b), theta = atan2(b, a); //极坐标
    theta += d * pi / 180.0; //弧度制
    //cout << r << ' ' << theta << endl;
    
    double x = cos(theta) * r, y = sin(theta) * r;
    cout << fixed << setprecision(7) << x << ' ' << y << endl;
}

C - XX to XXX

题意

给定串s和t,对于任意\(s_i=s_{i+1}\),可以在i+1处往后面拼接任意个\(s_i\),问能否通过若干次这样的操作,使得s和t相等

解法

先把s 和 t 进行如下处理,把每一个连续段变成“字符+该字符数量”的形式

(相当于是抽象出了特征字符)乱取的名字
然后就可以对变换后的两串(s->v1, t->v2)进行匹配操作:

  1. 如果当前位置字符不相等,则一定无法变换 (v1[i].first != v2[i].first);
  2. 如果当前位置的字符数量,v1比v2多也不行, 因为s只能扩增而不能缩减 (v1[i].second > v2[i].second);
  3. 根据题意,如果v1处字符只有一个也无法进行扩增 (v1[i].second < v2[i].second && v1[i].second < 2)。

Code

#include <bits/stdc++.h>

using namespace std;
typedef pair<char, int> pci;
vector <pci> v1, v2;

vector <pci> change (string s) {
    int n = s.size (), len = 1;
    vector <pci> v;
    for (int i = 1; i < n; i ++) {
        if (s[i] == s[i - 1])   len ++;
        else v.push_back ({s[i-1], len}), len = 1;
    }
    if (len)    v.push_back ({s[n-1], len});
    return v;
}

void test () {
    cout << "v1:\n";
    for (auto i : v1)    cout << i.first << ' ' << i.second << endl;
    cout << "v2:\n";
    for (auto i : v2)    cout << i.first << ' ' << i.second << endl;
}

int main () {
    string s, t;
    cin >> s >> t;
    if (s == t)     cout << "Yes";
    else {
        v1 = change (s), v2 = change (t);
        //test ();
        int n = v1.size (), m = v2.size ();
        if (n != m)     cout << "No";
        else {
            bool suc = true;
            for (int i = 0; i < n; i ++) {
                if (v1[i].first != v2[i].first) {
                    suc = false;
                    break;
                }
                if ((v1[i].second > v2[i].second) || (v1[i].second < v2[i].second && v1[i].second < 2)) {
                    suc = false;
                    break;
                }
            }
            if (suc)    cout << "Yes";
            else    cout << "No";
        }
    }
}
//pair<char, int> 连续段字符,数量

D - Circumferences

题源:abc259_d
人生中第一次做出D题于是就来发题解了

题目描述

给定n个圆(圆心坐标和半径r),以及起点和终点的坐标(这两点必在某个圆上)
已知 点可以沿着圆的边界(即在圆上移动),试判断能否从起点走到终点。

样例

Sample Input 1

4
0 -2 3 3
0 0 2
2 0 2
2 3 1
-3 3 3

Sample Output 1

Yes

Sample Input 2

3
0 1 0 3
0 0 1
0 0 2
0 0 3


Sample Output 2

No

分析

点一定是在圆上动的,所以当走到两圆交界处的时候就可以顺势走到另一个圆上。
(这里没法放图片,所以可以去原题看样例的截图来辅助来理解)
那么此时就等价于,在这两个圆之间建立一条无向边,于是问题就转化为:求 起点所在的圆 到 终点所在的圆的最短路

分析完毕,梳理一下要做的事:

  1. 找到起点和终点所在的圆的编号,记录为st和ed;
  2. 把所有两两相交的圆找到,然后建边(注意特判同心圆不可达的情况)
  3. 跑最短路的板子

Code

代码写的很潦草,轻喷
SPFA

#include <bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> pii;
const int N = 3005*3005, inf = 1e18;
int h[N], ee[N], ne[N], w[N], idx;
int sx, sy, fx, fy, st = 0, ed = 0, n;
int dis[N];
bool vis[N];
//int a[N][N];

void add (int a, int b, int c) {
    ee[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}

struct Node {
    int x, y, r;
    bool operator<(const Node &t)const {
        return x < t.x;
    }
}e[N];

void spfa () {
    queue<int>q;
    for (int i = 1; i <= n; i ++)   dis[i] = inf;
    dis[st] = 0;
    q.push(st);
    vis[st]  = true;
    
    while (!q.empty()) {
        int t = q.front();
        q.pop();
        vis[t] = false;
        
        for (int i = h[t]; i != -1; i = ne[i]) {
            int j = ee[i];
            if (dis[j] > dis[t]+ w[i]) {
                dis[j] = dis[t] + w[i];
                if (!vis[j])
                    q.push (j), vis[j] = true;
            }
        }
    }
    //for (int i = 1; i <= n; i ++)   cout << dis[i] << endl;
    // cout << dis[ed] << endl;

    if (dis[ed] != inf)  cout << "Yes\n";
    else    cout << "No\n";
}

signed main () {
    cin >> n;
    cin >> sx >> sy >> fx >> fy;
    for (int i = 1; i <= n; i ++) {
        int x, y, r;
        cin >> x >> y >> r;
        e[i] = {x, y, r}; 
    }
    //sort (e + 1, e + n + 1);

    for (int i = 1; i <= n; i ++) {
        if (st && ed)   break;
        int x = e[i].x, y = e[i].y, r = e[i].r;
        if ((x-sx)*(x-sx) + (y-sy)*(y-sy) == r*r)   st = i;
        if ((x-fx)*(x-fx) + (y-fy)*(y-fy) == r*r)   ed = i;
    }
    //cout << "st=" << st << ", ed=" << ed << endl;

    //建图
    memset (h, -1, sizeof h);
    for (int i = 1; i <= n; i ++) {
        int x = e[i].x, y = e[i].y, r = e[i].r;
        for (int j = i + 1; j <= n; j ++) {
            int xx = e[j].x, yy = e[j].y, rr = e[j].r;
            //if (x == xx && y == yy && r != rr)  continue;
            int d1 = (x-xx)*(x-xx) + (y-yy)*(y-yy);
            int d2 = (r+rr)*(r+rr);
            if (d1 != 0 && d1 <= d2) {
                //cout << "i=" << i << ", j=" << j << endl;
                add (i, j, 1), add (j, i, 1);
                //a[i][j] = a[j][i] = 1;
            }
        }
    }

    spfa ();
}

//走边框,看看能否走到
//z找圆的交点
//抽象建图,如果两个圆有交点的话就建立一条边

难得做出图论题...

E - LCM on Whiteboard

题意

给定n个数字,每个数字都给出m对{p,e},m对\(p^e\)的乘积构成该数字a[i]。现可把n中任意一个数字a[i],i\(\in\)[1,n]替换成1,求剩余数字(a[1],a[2],...,a[i-1],a[i+1],...,a[n])组成的LCM共有多少种可能。

分析

首先,LCM有一个性质,其值为所有最高幂次的质因子的乘积。

举个例子:
\(LCM(2^4\times 3^1, 3^2\times 2^3\times 5^3, 5^2\times 3^3)=2^4\times 3^3\times 5^3\)

因此我们要做的就是,统计不同质因子的最大值(且该最大值只能出现一次,否则会有重复

坑:若所有a[i]都有LCM,则整体的LCM与其中一个重合,需-1

Code

#include <bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> pii;
const int N = 1e9 + 5;
map<int, int> maxn, tot;
//bool vis[N];

signed main () {
    int n;  cin >> n;
    vector <pii> a[n+1];
    for (int i = 1; i <= n; i ++) {
        int m;  cin >> m;
        while (m --) {
            int p, x;   cin >> p >> x;
            a[i].push_back ({p, x});
            if (x > maxn[p])  maxn[p] = x, tot[p] = 1; //更新最大值
            else if (x == maxn[p])  tot[p] ++;
        }
    }

    int ans = 1;
    int cnt = 0; //用来防止重合的
    for (int i = 1; i <= n; i ++) {
        int find = 0;
        for (auto j : a[i]) {
            int p = j.first, x = j.second;
            if (x == maxn[p] && tot[p] == 1)  find = 1;
        }
        ans += find;
        if (find)   cnt ++; //是否每次都有更新LCM
    }
    //cout << ans << endl;
    if (cnt == n)   cnt = 1;
    else    cnt = 0;
    cout << ans - cnt << endl;
}

F - Select Edges

G - Grid Card Game

posted @ 2022-07-09 23:53  Sakana~  阅读(151)  评论(0编辑  收藏  举报