Dashboard - Codeforces Round 883 (Div. 3) - Codeforces
A. Rudolph and Cut the Rope
题意:
在一垂直于地面的直线上有n个点,每个点的高度分别为ai,每个点分别有一条长度为bi的绳子与糖果相连,问最少切断几条绳子能使糖果落地。
题解:
贪心。所有固定高度ai>长度bi的绳子需要被切断。
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 2e5 + 10, INF = 0x3f3f3f3f;
void solve()
{
int n, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
int a, b;
scanf("%d%d", &a, &b);
if (b < a)++ans;
}
printf("%d\n", ans);
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
B. Rudolph and Tic-Tac-Toe
题意:
三个人下井字棋,棋子分别为'X'、'O'、'+',空白的地方是'.',问赢家是谁(或者没有赢家,保证最多只有一个赢家)
题解:
模拟一下。
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 2e5 + 10, INF = 0x3f3f3f3f;
char mp[5][5];
void solve()
{
for (int i = 1; i <= 3; ++i)
scanf("%s", mp[i] + 1);
for (int i = 1; i <= 3; ++i)
{
if (mp[i][1] == mp[i][2] && mp[i][2] == mp[i][3] && mp[i][1] != '.')
{
printf("%c\n", mp[i][1]);
return;
}
if (mp[1][i] == mp[2][i] && mp[2][i] == mp[3][i] && mp[1][i] != '.')
{
printf("%c\n", mp[1][i]);
return;
}
}
if (mp[1][1] == mp[2][2] && mp[2][2] == mp[3][3] && mp[2][2] != '.')
printf("%c\n", mp[2][2]);
else if (mp[1][3] == mp[2][2] && mp[2][2] == mp[3][1] && mp[2][2] != '.')
printf("%c\n", mp[2][2]);
else
printf("DRAW\n");
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
C. Rudolf and the Another Competition
题意:
有n人打ICPC赛制的比赛(排名优先按解题数降序,解题数一样按罚时升序),比赛共m题,时长为h,第i名选手解出第j题的时间为,问在所有人都按最优顺序做题时选手1的排名。
题解:
贪心。每名选手的最优做题顺序就是按解题时间升序,可以求出所有选手最优的题数和罚时,遍历一遍求在选手1前面的有几名即可。(存罚时要开longlong...被hack了)
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 2e5 + 10, INF = 0x3f3f3f3f;
LL a[N], w[N], cost[N];
void solve()
{
int n, m, t, ans = 1;
scanf("%d%d%d", &n, &m, &t);
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
scanf("%lld", &a[j]);
sort(a + 1, a + 1 + m);
w[i] = cost[i] = 0;
for (int j = 1, st = a[1]; j <= m && st <= t; ++j, st += a[j])
++w[i], cost[i] += st;
}
for (int i = 2; i <= n; ++i)
{
if (w[i] > w[1] || (w[i] == w[1] && cost[i] < cost[1]))
++ans;
}
printf("%d\n", ans);
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
D. Rudolph and Christmas Tree
题意:
在平面直角坐标系中有n个顶点为(0,yi),底边平行于x轴且长度为d,高为h的全等等腰三角形(建议直接看题目里的图)。问这些三角形组成的图像的总面积(重叠部分不重复计算)
题解:
算总面积减去重叠部分面积(每个重叠部分是个相似三角形)。
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 2e5 + 10, INF = 0x3f3f3f3f;
int a[N];
void solve()
{
int n, d, h;
scanf("%d%d%d", &n, &d, &h);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
double ans = 0.5 * n * d * h;
for (int i = 1; i < n; ++i)
{
if (a[i] + h > a[i + 1])
{
int dh = a[i] + h - a[i + 1];
ans -= 0.5 * d * dh / h * dh;
}
}
printf("%.8lf\n", ans);
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
E2. Rudolf and Snowflakes (hard version)
题意:
定义一个雪花:(这是AI翻译...)初始时,图只有一个顶点。 然后,将更多的顶点添加到图中。初始顶点与k个新顶点(k>1)相连。 每个只与另一个顶点相连的顶点再与k个新顶点相连。此步骤至少要执行一次。 下图显示了k=4时的最小可能雪花。
题目给出一个n(n<=1e18)问是否存在一个有n个点的雪花。
题解:
设雪花最后有t+1层(从只有一个顶点开始执行了t次添加操作),那这个雪花的点的数量为k^0+k^1+k^2+...+k^t (k>1,t>1)。这是一个等比数列求和,因为k最少为2,那当k为2时,t的最大值不超过60(2^60>1e18),所以我们可以枚举所有的t,对于每个t求出是否存在k^0+k^1+...+k^t=n。可以考虑二分k,最终找到一个k^0+k^1+...+k^t<=n,再判断是否相等(其实可以直接算...因为不太信任double的精度所以我是二分写的,算等比数列求和还是暴力算的,这种做法时间复杂度非常高跑了1800ms,很多地方能优化)
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 2e5 + 10, INF = 0x3f3f3f3f;
LL n;
bool cheak(LL k, int t)
{ //直接算很容易爆LL所以要在计算过程中加好多步判断会不会爆的
LL s = 1, sum = 0;
for (int i = 0; i <= t; ++i)
{
if (i)
{
if (1.0 * s * k > 1e19)return 0;
if (s * k > n)return 0;
s *= k;
}
sum += s;
if (sum > n)return 0;
}
return 1;
}
LL get_sum(LL k, int t)
{
LL s = 1, sum = 0;
for (int i = 0; i <= t; ++i)
{
sum += s;
s *= k;
}
return sum;
}
void solve()
{
scanf("%lld", &n);
for (int i = 2; i < 60; ++i)
{
LL l = 2, r = 1e9;
//t最小为2,要保证k^2>1e18只需要k最大为1e9
while (l < r)
{
LL mid = l + r + 1 >> 1;
if (cheak(mid, i))
l = mid;
else
r = mid - 1;
}
if (get_sum(l, i) == n)
{
printf("YES\n");
return;
}
}
printf("NO\n");
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
F. Rudolph and Mimic
题意:
(建议是看原文...)在房间中有n个物体,其中有一个是变形怪,变形怪可以把自己的物品种类变成任意的初始存在的物品的种类,刚开始会给出每个物品的物品种类,a1,a2,a3,...,an
你可以扔掉任意个在房间中的物品(可以是0),操作为先输出"- ",然后输出要删除的物品个数k,后面跟k个索引(上一次给出物品种类时的下标,从1开始)在你扔掉物品之后,会再次给出剩余的每个物品的物品种类,但是房间中剩余的物品顺序将会被打乱,并且变形怪会更改他的物品种类(也可以保持不变),变形怪不能连续两次选择不变。
如果把变形怪扔了会是Wrong answer
在确定变形怪时,输出cout"! "<<i<<endl;(i为变形怪的索引)
你最多能进行五次操作。
题解:
因为物品的顺序每次都会打乱,所以有用的数据是每种物品种类中物品的数量。
刚开始并不能确定变形怪在哪种物品中,因此只能一直选择扔0件物品等变形怪变形。
记操作前每种物品种类为cnt[i],操作后每种物品种类为c[i],当c[i]>cnt[i]时,说明变形怪将他的物品种类更改成了i,这时候就能扔掉所有的种类不为i的物品。因为变形怪最多连续保持不变一次,所以最多两次操作就能使房间中只剩一种物品和变形怪。
接下来再一直扔0件物品等变形怪变形,当出现已经扔完的物品种类时就能确定变形怪了。
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 2e2 + 10, INF = 0x3f3f3f3f;
void solve()
{
int n, cnt[10] = { 0 }, flag = 1;
cin >> n;
for (int i = 1, x; i <= n; ++i)
{
cin >> x;
cnt[x]++;//计数初始每种种类的物品个数
}
while (flag)
{
cout << "- 0" << endl;
int a[N], c[10] = { 0 };
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
c[a[i]]++;//计数变化之后的物品个数
}
//如果某种物品变多了,说明怪物变成了那种物品,删除所有其他种类物品
for (int i = 1; i <= 9; ++i)
{
if (c[i] > cnt[i])
{
memset(cnt, 0, sizeof cnt);
cnt[i] = c[i];
cout << "- " << n - cnt[i];
for (int j = 1; j <= n; ++j)
{
if (!cnt[a[j]])
cout << " " << j;
}
cout << endl;
n = cnt[i];
flag = 0;
break;
}
}
}
while (1)
{
int a[N];
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 1; i <= n; ++i)
{
if (!cnt[a[i]])//怪物变成了已经被删除的物品
{
cout << "! " << i << endl;
return;
}
}
cout << "- 0" << endl;
}
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
G. Rudolf and CodeVid-23
题意:
看看AI翻译的吧:
一种名为“CodeVid-23”的新型病毒在程序员中传播开来。作为一名程序员,鲁道夫无法避免感染。
有n个症状,编号从1到n,当感染时可能出现。最初,鲁道夫有其中的一些症状。他去药店购买了m种药物。
对于每种药物,已知需要服用的天数和它能够缓解的症状。不幸的是,药物通常会有副作用。因此,对于每种药物,也已知在服用时可能出现的症状。
阅读说明后,鲁道夫意识到同时服用多种药物对健康非常不利。
鲁道夫希望尽快康复。因此,他请你计算去除所有症状所需的最少天数,或者说这是不可能的。
输入 第一行包含一个整数t(1≤t≤100)——测试用例的数量。
接下来是每个测试用例的描述。
每个测试用例的第一行包含两个整数n和m(1≤n≤10,1≤m≤103)——症状和药物的数量。
每个测试用例的第二行包含一个长度为n的字符串,由字符0和1组成——鲁道夫的症状描述。如果字符串的第i个字符是1,表示鲁道夫有第i个症状,否则他没有。
然后是3m行——药物的描述。
每种药物描述的第一行包含一个整数d(1≤d≤103)——药物需要服用的天数。
药物描述的下两行包含两个长度为n的字符串,由字符0和1组成——它所能缓解的症状和副作用的描述。
在这两行中,第一行的第i个位置上的1表示该药物能够缓解第i个症状,否则为0。
在这两行的第二行中,第i个位置上的1表示服用药物后会出现第i个症状,否则为0。
不同的药物可能有相同的症状和副作用集合。如果一种药物能够缓解某种症状,那么它不会成为副作用。
所有测试用例中m的总和不超过103。
输出 对于每个测试用例,输出一个整数,表示鲁道夫去除所有症状所需的最少天数。如果这是不可能的,输出-1。
题解:
n<=10,症状还是01的串,一眼状压。设吃药前状态为f,某种药缓解的症状状态为a,副作用的状态为b,那吃药之后先染上副作用f |= b,然后缓解症状f -= f & a。
对于在每种状态f而言,吃每种药都有di时间并使状态变为另一种f1,相当于状态f与状态f1之间有一条花费为di的有向边,题目就变为了问在有向图中从初始状态到状态0的最短路,直接套堆优化dijkstra板子(别的最短路算法也行)
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 1e3 + 10, INF = 0x3f3f3f3f;
int n, m, sta, dist[1 << 10], d[N], a[N], b[N];
int getf()//二进制转十进制
{
char ch[16];
scanf("%s", ch + 1);
int res = 0;
for (int i = 1; ch[i]; ++i)
res = res * 2 + ch[i] - '0';
return res;
}
void dijkstra()
{
priority_queue<PII, vector<PII>, greater<PII> >q;
q.push({ 0,sta });
while (q.size())
{
int t = q.top().first, f = q.top().second;
q.pop();
if (dist[f] <= t)continue;
dist[f] = t;
for (int i = 1; i <= m; ++i)
{
int tf = f | b[i];
tf -= tf & a[i];
q.push({ t + d[i],tf });
}
}
}
void solve()
{
scanf("%d%d", &n, &m);
sta = getf();
for (int i = 1; i <= m; ++i)
{
scanf("%d", &d[i]);
a[i] = getf();
b[i] = getf();
}
memset(dist, 0x3f, sizeof dist);
dijkstra();
if (dist[0] != INF)
printf("%d\n", dist[0]);
else
printf("-1\n");
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}