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
题意
给一点坐标和旋转角度,求旋转后的坐标
解法
看了题解学到两个新的函数:
- hypot(): hypot(x,y)=(可传2-3个参数)
- atan2(): atan2(x,y)=,返回夹角,范围为,可区分象限 (有了这个函数就不用分类讨论象限了)
别忘了将转为弧度制:
最后化为极坐标即可。
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,对于任意,可以在i+1处往后面拼接任意个,问能否通过若干次这样的操作,使得s和t相等
解法
先把s 和 t 进行如下处理,把每一个连续段变成“字符+该字符数量”的形式
(相当于是抽象出了特征字符)乱取的名字
然后就可以对变换后的两串(s->v1, t->v2)进行匹配操作:
- 如果当前位置字符不相等,则一定无法变换 (v1[i].first != v2[i].first);
- 如果当前位置的字符数量,v1比v2多也不行, 因为s只能扩增而不能缩减 (v1[i].second > v2[i].second);
- 根据题意,如果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
分析
点一定是在圆上动的,所以当走到两圆交界处的时候就可以顺势走到另一个圆上。
(这里没法放图片,所以可以去原题看样例的截图来辅助来理解)
那么此时就等价于,在这两个圆之间建立一条无向边,于是问题就转化为:求 起点所在的圆 到 终点所在的圆的最短路
分析完毕,梳理一下要做的事:
- 找到起点和终点所在的圆的编号,记录为st和ed;
- 把所有两两相交的圆找到,然后建边(注意特判同心圆不可达的情况)
- 跑最短路的板子
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对的乘积构成该数字a[i]。现可把n中任意一个数字a[i],i[1,n]替换成1,求剩余数字(a[1],a[2],...,a[i-1],a[i+1],...,a[n])组成的LCM共有多少种可能。
分析
首先,LCM有一个性质,其值为所有最高幂次的质因子的乘积。
举个例子:
因此我们要做的就是,统计不同质因子的最大值(且该最大值只能出现一次,否则会有重复)
坑:若所有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;
}