牛客IOI周赛22-普及组 题解
牛客IOI周赛22-普及组
简单得就nm离谱都ak不了,初中生的做的题,太丢人了。
T1 战争尾声
- 题意:大体意思就是在一片网格图中,给\(n\)个点,然后找到一个点,这个点到所有点距离相同。\(1 < n <= 200\)并且所有点都是整数,并且地图大小\(200\times200\)。
- 题解:看到范围就知道直接遍历就行,没啥好说的
- 代码:
#include<iostream>
#include <cmath>
using namespace std;
const int N = 500;
int ans_cnt = 0;
const double eps = 1e-4;
struct node {
double x, y;
}a[N];
struct Node {
int x, y;
} ans[N*N+99];
bool equal(double a, double b) {
return (fabs(a - b) < eps);
}
double dis(int X, int Y, node a) {
double x = X, y = Y;
return (a.x - x) * (a.x - x) + (a.y - y) * (a.y - y);
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y;
}
for (int Y = 1; Y <=200; Y++) {
for (int X = 1; X <= 200; X++) {
double x = X, y = Y;
double Dis = dis(x, y, a[1]);
bool f = 1;
for (int i = 1; i <= n; i++) {
if (!equal(Dis, dis(x, y, a[i]))) {
f = 0;
break;
}
}
if (f) {
ans[++ans_cnt] = { X, Y};
}
}
}
int MIx = 2001;
int MIy = 2020;
int pos;
for (int i = 1; i <= ans_cnt; i++) {
if (ans[i].x < MIx) {
MIx = ans[i].x;
MIy = ans[i].y;
pos = i;
} else if (ans[i].x == MIx) {
if (ans[i].y < MIy) {
MIy = ans[i].y;
pos = i;
}
}
if (i == ans_cnt) {
cout << ans[pos].x << " " << ans[pos].y << endl;
}
}
if (ans_cnt == 0)
cout << "War is cruel.\n";
return 0;
}
T2 签订协议
- 题意:给\(n\)个人,然后每个人都有权值,然后必须要从\(1\)到\(n\)然后围成一圈遍历,遍历到权值最大的,把这人删除然后继续从下一人开始遍历,问遍历几次删除所有人。
- 题解:把每个人的位置存一下,用权值关键字排个序从大到小,然后就遍历这个数组,如果下一个元素的位置比当前要小,那么\(ans++\),因为必然会转一圈,然后遍历一遍就行。
- 代码:
#include <iostream>
#include <algorithm>
typedef long long ll;
using namespace std;
const ll N = 1e6 + 99;
struct node {
int data, id;
bool operator<(node rhs)const {
return data > rhs.data;
}
}a[N];
ll b[N];
signed main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].data;
a[i].id = i;
}
sort(a + 1, a + 1 + n);
ll ans = 1;
for (int i = 1; i <= n; i++) {
b[i] = a[i].id;
if (b[i] < b[i-1])ans++;
}
cout << ans << endl;
}
T3 照看小猫
- 题意:给\(n\)个小猫,要给这些猫起名字,每个猫名字要独一无二,\(a_{i}\)表示第\(i\)个猫所能取的最长的长度,只能是小写字母\(a\)到\(z\),求所有方案数。
- 题解:一看到计数题自己就不自觉地和高深的容斥扯上关系。其实长度短的会对长度长的有影响,所以先排序。预处理出来一个小猫名字长度为\(i\)时的方案数,然后从前往后遍历数组,每次让\(ans \times (cnt[i] - (i-1))\),如果前面猫的数量太多,并且当前猫的名字长度太短,那么必然\((cnt[i] - (i-1)) < 0\)那么就没有办法了,无解。
- 代码:
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll N = 1e5 + 9;
const ll mod = 77797;
ll q_mi(ll a, ll k, ll mod) {
ll x = a;
ll ret = 1;
while (k) {
if (k & 1) {
(ret *= x)%= mod;
}
k>>=1;
(x *= x)%= mod;
}
return ret;
}
ll a[N];
ll cost[11];
signed main() {
ll n;
cin >> n;
for (ll i = 1; i <= 10; i++) {
(cost[i] = q_mi(26, i, mod) + cost[i-1])%=mod;
}
ll ans = 1;
for (ll i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + 1 + n);
for (ll i = 1; i <= n; i++) {
if ( cost[a[i]] - (i-1) < 0) {
cout << -1 << endl;return 0;
}
else {
(ans *= (cost[a[i]] - ( i - 1)) )%= mod;
}
}
cout << ans << endl;
}
T4 路线规划
- 题意:给你一个\(n\times m\)的无向完全图,有边权,求从\(1\)要走到所有点并且走回\(1\),走最少的路,并且经过的边权加和最少。
- 题解:随便搞了搞就发现是个最小生成树,因为走的路最少,那就是边的数量最少,又要遍历所有的边,所以是一个树,然后边权加和最少,那么走两边发现是最小生成树的边权\(*2\)。
- 代码:
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const ll N = 2e5 + 99;
const ll M = 2e6 + 99;
struct edge {
int u, v, w;
}a[M];
bool cmp(edge a, edge b) {return b.w > a.w;
}
bool vis[N];
ll ans = 0;
ll f[N];
ll Find (ll x) {return f[x] == x?x:f[x] = Find(f[x]);}
signed main() {
ll n, m;
ios::sync_with_stdio(0);
cin >> n >> m;
for (int i = 1;i <= n; i++) {
f[i] = i;
}
for (int i = 1; i<= m; i++) {
int u, v, w;
cin >> u >> v >> w;
a[i] = {u, v, w};
}
sort(a + 1, a + 1 + m, cmp);
for (int i = 1; i <= m; i++) {
ll x = a[i].u;
ll y = a[i].v;
ll fx = Find(x);
ll fy = Find(y);
if (fx == fy)continue;
f[fx] = fy;
//cout << x << "?" << y << endl;
ans += a[i].w;
}
cout << ans * 2 << endl;
}