目录
A. Clam and Fish
https://ac.nowcoder.com/acm/contest/5668/A
有鱼的时候就捕鱼,没有鱼有蛤蜊时做鱼食,
既没有鱼也没有蛤蜊时如果有鱼食就钓鱼,
最后,如果还有鱼食剩余,拿出剩余本来是做鱼食的时间,改为钓鱼
#include <bits/stdc++.h>
using namespace std;
int n;
string s;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> s;
int res = 0, cnt = 0;
for (int i = 0; i < n; i++) {
if (s[i] == '2' || s[i] == '3') res++;
else if (s[i] == '1') cnt++;
else if (s[i] == '0' && cnt) {
res++;
cnt--;
}
}
cout << res + (cnt / 2) << endl;
}
return 0;
}
B. Classical String Problem
https://ac.nowcoder.com/acm/contest/5668/B
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e6 + 5;
char s[MAXN], op[5];
int main() {
int q, n;
scanf("%s", s);
scanf("%d", &q);
int cnt = 0, len = strlen(s);
while (q--) {
scanf("%s%d", op, &n);
if (op[0] == 'A') {
printf("%c\n", s[(cnt + n - 1) % len]);
} else {
cnt = (cnt + n + len) % len;
}
}
return 0;
}
C. Operation Love · 几何
https://ac.nowcoder.com/acm/contest/5668/C
识别左右手
方法1:将旋转的图形掰正
几个知识点:
- 直线的斜率可以通过 c++函数
a
t
a
n
2
(
Δ
y
,
Δ
x
)
atan2(\Delta y,\Delta x)
atan2(Δy,Δx) 求出,其返回的是弧度,即当斜率为90°时
a t a n 2 ( 90 ° ) = 1.57 atan2(90°)=1.57 atan2(90°)=1.57 - c++的 sin ( x ) \sin(x) sin(x) cos ( x ) \cos(x) cos(x) 这些函数都是使用弧度制的
- 点
(
x
p
,
y
p
)
(x_p,y_p)
(xp,yp) 绕某一点
(
x
o
,
y
o
)
(x_o,y_o)
(xo,yo) 旋转 顺时针旋转θ角度后的新坐标
x = ( x p − x o ) cos θ − ( y p − y o ) sin θ + x o y = ( y p − y o ) cos θ + ( x p − x o ) sin θ + y o x=(x_p-x_o)\cos\theta-(y_p-y_o)\sin\theta+x_o\\ y=(y_p-y_o)\cos\theta+(x_p-x_o)\sin\theta+y_o x=(xp−xo)cosθ−(yp−yo)sinθ+xoy=(yp−yo)cosθ+(xp−xo)sinθ+yo
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-6; // 坑 1e-8就过不去
const double pi = acos(-1.0);
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
else return 1;
}
//判断小数和0是否等于
struct Point {
double x, y;
Point() {}
Point(double _x, double _y) { x = _x, y = _y; }
void input() { scanf("%lf%lf", &x, &y); }//输入
void output() { printf("%.2f %.2f\n", x, y); } //输出
Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }
Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }
Point operator*(const double &k) const { return Point(x * k, y * k); }
Point operator/(const double &k) const { return Point(x / k, y / k); }
bool operator==(Point b) const { return sgn(x - b.x) == 0 && sgn(y - b.y) == 0; }
bool operator<(Point b) const { return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x; }
double operator^(const Point &b) const { return x * b.y - y * b.x; }
//叉积
double operator*(const Point &b) const { return x * b.x + y * b.y; }
//点积
double distance(Point p) { return hypot(x - p.x, y - p.y); }
//两点之间的距离
};
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s;
e = _e;
}
bool operator==(Line v) { return (s == v.s) && (e == v.e); }
double angle() {
double k = atan2(e.y - s.y, e.x - s.x);
if (sgn(k) < 0)k += pi;
if (sgn(k - pi) == 0) k -= pi;
return k;
}//返回直线倾斜角 0<=angle<pi
int relation(Point p) {
int c = sgn((p - s) ^ (e - s));
if (c < 0) return 1; //点在直线的左侧
else if (c > 0) return 2;//点在直线的右侧
else return 3;//点在直线上
}//判断点与直线的关系
};
Point p[25], tmp;
Line L1, L2;
int u1, v1, u2, v2;
int main() {
int T;
scanf("%d", &T);
while (T--) {
for (int i = 0; i < 20; i++) p[i].input();
for (int i = 0, j = 19; i < 20; i++, j = i - 1) {
if (sgn(9.0 - p[i].distance(p[j])) == 0) { // 找到最长的边 作为将来的x轴
if (p[i].x > p[j].x) {
L2 = {p[j], p[i]};
u2 = j, v2 = i;
} else {
L2 = {p[i], p[j]};
u2 = i, v2 = j;
}
break;
}
}
//绕较小的端点u2点旋转
double angle = L2.angle();
for (int i = 0; i < 20; i++) {
tmp.x = (p[i].x - p[u2].x) * cos(angle) - (p[i].y - p[u2].y) * sin(angle) + p[u2].x;
tmp.y = (p[i].y - p[u2].y) * cos(angle) + (p[i].x - p[u2].x) * sin(angle) + p[u2].y;
p[i] = tmp;
}
for (int i = 0, j = 19; i < 20; i++, j = i - 1) {
if (sgn(6.0 - p[i].distance(p[j])) == 0) { // 将边长为6的那条边作为y轴
if (p[i].y > p[j].y) L1 = {p[j], p[i]};
else L1 = {p[i], p[j]};
u1 = i, v1 = j;
break;
}
}
if (p[u2].x > p[v2].x) L2 = {p[v2], p[u2]}; // 根据新生成的坐标生成x轴
else L2 = {p[u2], p[v2]};
int f = 0;
for (int i = 0; i < 20; i++) {
if (i != u1 && i != v1 && i != u2 && i != v2) {
int k1 = L1.relation(p[i]);//判断直线与点的位置关系
int k2 = L2.relation(p[i]);
if (k1 == 2 && k2 == 1) f = 0; // 右手
else if (k1 == 1 && k2 == 1) f = 1; // 左手
else if (k1 == 1 && k2 == 2) f = 0;
else if (k1 == 2 && k2 == 2) f = 1;
break;
}
}
if (f) {
puts("left");
} else {
puts("right");
}
}
return 0;
}
方法2:叉积
选择长度为6的边和长度为9的边作为两个向量,
用右手判断,四指握拳方向与向量6指向向量9的方向一致,
大拇指朝远离自己的方向即为右手,朝向自己即为左手
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-5;
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
else return 1;
}
//判断小数和0是否等于
struct Point {
double x, y;
Point() {}
Point(double _x, double _y) { x = _x, y = _y; }
void input() { scanf("%lf%lf", &x, &y); }//输入
void output() { printf("%.2f %.2f\n", x, y); } //输出
Point operator - (const Point &b) const { return Point(x - b.x, y - b.y); }
Point operator + (Point b) { return Point(x + b.x, y + b.y); }
double operator ^ (const Point &b) const { return x * b.y - y * b.x; }
//叉积
double distance(Point p) { return hypot(x - p.x, y - p.y); }
//两点之间的距离
};
typedef Point Vector;
Point p[25];
Vector v6, v9;
int main() {
int T;
scanf("%d", &T);
while (T--) {
for (int i = 0; i < 20; i++) {
p[i].input();
}
int a, b;
for (int i = 0, j = 19; i < 20; i++, j = i - 1) {
if (sgn(9.0 - p[i].distance(p[j])) == 0) {
a = i, b = j;
break;
}
}
for (int i = 0, j = 19; i < 20; i++, j = i - 1) {
if (sgn(6.0 - p[i].distance(p[j])) == 0) {
if (i == a) {//两条边的交点为点 p[i]
v6 = p[j] - p[i];
v9 = p[b] - p[i];
} else if (i == b) {
v6 = p[j] - p[i];
v9 = p[a] - p[i];
} else if (j == a) {//交点为 p[j]
v6 = p[i] - p[j];
v9 = p[b] - p[j];
} else {// j==b
v6 = p[i] - p[j];
v9 = p[a] - p[j];
}
break;
}
}
if (sgn(v6 ^ v9) < 0) {
puts("right");
} else { // 不会有=0
puts("left");
}
}
return 0;
}
D. Points Construction Problem
https://ac.nowcoder.com/acm/contest/5668/D
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 1e3 + 10;
int n, m, k;
pii res[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> m;
if ((m & 1) || m > 4 * n) {
cout << "No" << endl;
continue;
}
/*
* 显然 m<=4n
*
* 假设所有的黑子都在一个矩形中 a行b列
* 不管是塞满还是没塞满 至少可以提供 2(a+b)对
* 所以 在 n<=ab 的前提下 m>= 2(a+b)
* 暴力枚举所有 a+b 查看m是否在范围内
* */
int a = 1, b = 1;
while (a * b < n) {
if (a < b)a++;
else b++;
}
// 矩形内部的黑子最多的情况下 m还比当前能够匹配的对数少 显然是不可能的了
if (2 * (a + b) > m) {
cout << "No" << endl;
continue;
}
int cnt = 2 * (a + b);
int id = 0;//定点最后一个黑子的位置
int f = 0;
for (int i = 1; i <= a; i++) {
for (int j = 1; j <= b; j++) {
res[++id] = {i, j};
if (id == n) {
f = 1;
break;
}
}
if (f) break;
}
// 对数不够时 移动矩形里的黑子
// 从 (a+1,b+1) 开始沿斜线摆放
int x = a + 1, y = b + 1;
while (cnt < m) {
// 如果在边缘 每次移动 只会增加2对
if (res[id].first == 1 || res[id].second == 1)
cnt += 2;
else cnt += 4;//否则每次都有4对增加
res[id--] = {x, y};
x++;
y++;
}
id++;
// 如果一不小心增过头了 只可能多了2个
// 就移动黑子到另一个也被移出去的黑子 相邻的位置
if (cnt == m + 2) {
//只往外移动了一个 没有共患难的黑子
// 就移动到 矩形边缘的一个黑子的旁边
if (id == n) {
res[id] = {1, 0};
} else {
res[id] = {res[id + 1].first, res[id + 1].second + 1};
}
}
cout << "Yes" << endl;
for (int i = 1; i <= n; i++) {
cout << res[i].first << " " << res[i].second << endl;
}
}
return 0;
}
E. Two Matchings · dp
https://ac.nowcoder.com/acm/contest/5668/E
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 0x3f3f3f3f3f3f3f3f;//inf=(1ll<<60)
const int N = 1e6 + 10;
ll a[N];
ll dp[N];
int n;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n);
ll res = 0;
for (int i = 2; i <= n; i += 2) {
res += a[i] - a[i - 1];
}
for (int i = 0; i <= n; i++) {
dp[i] = inf;
}
dp[4] = a[4] + a[3] - a[2] - a[1]; // 当匹配对数有偶数对时 显然(a[n-3],a[n-1]) (a[n-2],a[n]) 更优
if (n >= 6) // 当匹配对数有奇数对时 需要让其中三组配对成 (a[n-1],a[n-3]) (a[n-2],a[n-5]) (a[n-4],a[n]) dp找最优解
dp[6] = a[6] - a[4] + a[5] - a[2] + a[3] - a[1];
for (int i = 8; i <= n; i += 2) {
dp[i] = min(dp[i - 4] + a[i] - a[i - 2] + a[i - 1] - a[i - 3],
dp[i - 6] + a[i] - a[i - 2] + a[i - 1] - a[i - 4] + a[i - 3] - a[i - 5]);
}
res += dp[n];
cout << res << endl;
}
return 0;
}
F. Fraction Construction Problem · 构造
https://ac.nowcoder.com/acm/contest/5668/F
给出a,b 构造
c
d
−
e
f
=
a
b
\cfrac{c}{d}-\cfrac{e}{f}=\cfrac{a}{b}
dc−fe=ba
分两种情况讨论:
- 当
g
=
gcd
(
a
,
b
)
≠
1
g=\gcd(a,b)\not=1
g=gcd(a,b)=1 时,
a g + 1 b g − 1 b g = a b \cfrac{\frac{a}{g}+1}{\frac{b}{g}}-\cfrac{1}{\frac{b}{g}}=\cfrac{a}{b} gbga+1−gb1=ba - 当 gcd ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1 时, c f − d e d f = a b \cfrac{cf-de}{df}=\cfrac{a}{b} dfcf−de=ba (此为最简等式),由于a、b互质,如果d、f有相同的因子,则 c f − d e cf-de cf−de 肯定可以提取出一个因子,使得上下分子分母通分,这与 a、b互质矛盾,所以满足条件的 b b b 至少有两个及以上的质因数,再利用扩展欧几里得求出c、e即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y) { // ax+by=gcd(a,b)=1 x与y肯定不同号
if (b == 0) {
x = 1;
y = 0;
return a;
} else {
ll g = exgcd(b, a % b, x, y);
ll tmp = x;
x = y;
y = tmp - a / b * y;
return g;
}
}
ll a, b;
int primes[N], cnt; // 存储所有质数
bool vis[N]; // 存储每个数是否已被筛掉
void get_primes(int n) {// 线性筛法求素数
for (int i = 2; i <= n; i++) {
if (!vis[i])
primes[cnt++] = i;
for (int j = 0; i * primes[j] <= n; j++) {
vis[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
int main() {
get_primes(5000);
int T;
scanf("%d", &T);
while (T--) {
scanf("%lld%lld", &a, &b);
ll g = __gcd(a, b);
if (g != 1) {// a、b不互质
a /= g;
b /= g;
printf("%lld %lld 1 %lld\n", (a + 1), b, b);//c d e f
} else {// 互质
// 因为ab互质 且b=df a=cf-ed
// 如果df有相同因子 会使得ab不互质
ll d = 1;
for (int i = 0; i < cnt; i++) {
if (b % primes[i] == 0) {
while (b % primes[i] == 0) {
d *= primes[i];
b /= primes[i];
}
break;
}
}
ll f = b;
if (d == 1 || f == 1) {
printf("-1 -1 -1 -1\n");
} else {
ll c, e, f = b;
exgcd(f, d, c, e); // ax+by=gxd(a,b) 构造 cf-ed=a
c *= a;
e *= a;
if (c < 0) {
swap(c, e);
swap(d, f);
}
e = -e;
printf("%lld %lld %lld %lld\n", c, d, e, f);
}
}
}
return 0;
}
G. Operating on a Graph
https://ac.nowcoder.com/acm/contest/5668/G
卡我vector 吐血
#include <bits/stdc++.h>
using namespace std;
const int N = 8e5 + 10;
vector<int> e[N];
list<int> _list[N];
int n, m;
int fa[N];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void dfs(int x) {
for (int i = 1, sz = _list[x].size(); i <= sz; i++) {
//只取前sz个 链表会在下面的for里添加新的节点 后添加的节点是下次被染色的范围 不应该算进去
int u = _list[x].front();
_list[x].pop_front();
for (int v:e[u]) {
int fv = find(v);
if (fv != x) {
fa[fv] = x;
_list[x].splice(_list[x].end(), _list[fv]);
// 将 _list[fv] 的内容插入到 _list[x]末尾 并且删除_list[fv]里的内容
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T, q, o;
cin >> T;
while (T--) {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
fa[i] = i;
e[i].clear();
_list[i].clear();
_list[i].push_back(i);
}
for (int i = 1, u, v; i <= m; i++) {
cin >> u >> v;
u++;
v++;
e[u].push_back(v);
e[v].push_back(u);
}
cin >> q;
while (q--) {
cin >> o;
o++;
dfs(o);
}
for (int i = 1; i <= n; i++) {
cout << find(i) - 1 << (i == n ? "\n" : " ");
}
}
return 0;
}
H. Sort the Strings Revision
I. Sorting the Array
J. Operating on the Tree
K. Eleven Game
L. Problem L is the Only Lovely Problem
https://ac.nowcoder.com/acm/contest/5668/L
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
typedef long long ll;
char s[maxn];
int main()
{
scanf("%s",s);
int len=strlen(s);
int flag=1;
if(s[0]!='l'&&s[0]!='L')flag=0;
if(s[1]!='o'&&s[1]!='O')flag=0;
if(s[2]!='v'&&s[2]!='V')flag=0;
if(s[3]!='e'&&s[3]!='E')flag=0;
if(s[4]!='l'&&s[4]!='L')flag=0;
if(s[5]!='y'&&s[5]!='Y')flag=0;
if(flag)puts("lovely");
else puts("ugly");
return 0;
}