Codeforces Round 883 (Div. 3) A-G

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题的时间为t_{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;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值