【模拟】P9670 [ICPC 2022 Jinan R] Frozen Scoreboard|普及+

前言

C++算法与数据结构本博文代码打包下载

P9670 [ICPC 2022 Jinan R] Frozen Scoreboard

题目描述

2000 年以前的秦朝,曾举办过一次 ICPC 比赛。比赛中有 m m m 道题, n n n 个团队。我们知道每个队完成了多少道题以及其历史记录的总用时。这些称作该团队的结果,但是我们不知道他们每道题是否完成、用时多久。

最近,我们发现了每个队冻结的计分板。从该计分板上,我们可以看到每个队在比赛中的提交情况,但是不知道在最后一小时内提交的判分。一些人发现,对于一些队来说,他们冻结的计分板可能与他们在历史记录中的最终成绩相矛盾。

请根据最终得分和冻结的计分板,为各队创建一个与其最终结果和冻结的计分板一致的最终计分板。

按照以下规则来计算计分板和总分:

对于给定的队伍 i i i,它最终的计分板 是一个 m m m 元数组,其中第 j j j 个元素给出队伍 i i i 在第 j j j 题上的提交信息。

  • 如果队伍 i i i 没有提交问题 j j j,输出 .

  • 如果队伍 i i i 对问题 j j j 提交了 x x x 次但均未通过,输出 − x -x −x。

  • 否则,考虑队伍 i i i 在问题 j j j 的所有评测结果。每次提交都有一个提交时间,设第一个通过的评测是第 x x x 次评测,在第 y y y 分钟时提交。输出 + x / y +x/y +x/y,其中 0 ≤ y ≤ 299 0\leq y\leq299 0≤y≤299。

在最终计分板上,只考虑第一次通过的提交。同一分钟内可能有多次提交。

一个队伍的最终得分是该队伍完成了多少道题,即该队最终计分板上 +的个数。

一个队伍总用时按如下方式计算。如果队伍 i i i 在第 y y y 分钟完成了第 j j j 道题,在完成前有 x − 1 x-1 x−1 次失败的提交(即最终计分板上第 j j j 个问题的数为 + x / y +x/y +x/y),该问题的用时记为 20 ( x − 1 ) + y 20(x-1)+y 20(x−1)+y。 如果队伍 i i i 没有完成第 j j j 道题,该问题的用时记为 0 0 0,无论是否提交过。队伍 i i i 的总时间是每道题用时的总和。

输入格式

第一行包括两个整数 n , m    ( 1 ≤ n ≤ 1000 , 1 ≤ m ≤ 13 ) n,m\;(1\leq n\leq1000,1\leq m\leq13) n,m(1≤n≤1000,1≤m≤13),为队伍个数和题目个数。

接下来 n n n 组,描述每个队伍的最终得分和冻结的计分板。

第 i i i 组表示队伍 i i i。每一组中,第一行包括两个整数 a i , b i    ( 0 ≤ a i ≤ m , 0 ≤ b i ≤ 10 5 ) a_i,b_i\;(0\leq a_i\leq m,0\leq b_i\leq10^5) ai,bi(0≤ai≤m,0≤bi≤105),为队伍 i i i 在整场比赛中完成的题目个数和每道题的用时。这两个数字是比赛的最终结果。

接下来 m m m 行,描述队伍 i i i 在计分板上的内容。对于任意 1 ≤ j ≤ m 1\leq j\leq m 1≤j≤m,

  • 如果第 j j j 行是 +   x / y    ( 1 ≤ x ≤ 100 , 0 ≤ y ≤ 239 ) +\,x/y\;(1\leq x\leq100,0\leq y\leq239) +x/y(1≤x≤100,0≤y≤239),表示队伍 i i i 在第 y y y 分钟,第 x x x 次提交时通过了题 j j j。

  • 如果第 j j j 行是 ?   x   y    ( 1 ≤ x ≤ y ≤ 100 ) ?\,x\,y\;(1\leq x\leq y\leq100) ?xy(1≤x≤y≤100),表示队伍 i i i 没有在前四个小时中作出题 j j j。这个队伍提交了 y y y 次,其中 x x x 次在最后一小时内。最后一小时内且通过该题的提交记录会在冻结的计分板 上显示,但不会在最终计分板上显示。

  • 如果第 j j j 行是 − x -x −x,表示队伍 i i i 没有在前四小时内作出题 j j j。这个队伍在最后一个小时前提交了 x   ( 1 ≤ x ≤ 100 ) x\,(1\leq x\leq100) x(1≤x≤100) 次,且没有在最后一小时内做出题 j j j。

  • 如果第 j j j 行是一个单一的字符 .,表示队伍 i i i 没有提交过题 j j j。

输出格式

对于每个队伍 i i i,如果最终结果和冻结的计分板相矛盾,输出一行 No \texttt{No} No。否则,第一行输出 Yes \texttt{Yes} Yes,接下来 m m m 行,描述一种队伍 i i i 可能的计分板,满足最终结果和冻结的计分板。其中,第 j j j 行应该包括:

    • x / y   ( 1 ≤ x ≤ 100 , 0 ≤ y ≤ 299 ) +\,x/y\,(1\leq x\leq100,0\leq y\leq299) +x/y(1≤x≤100,0≤y≤299),如果队伍 i i i 在第 x x x 次提交,第 y y y 分钟完成了题 j j j,在这之前没有队伍通过这道题。不要在字符 /前后输出多余的空格。
  • − x   ( 1 ≤ x ≤ 100 ) -x\,(1\leq x\leq100) −x(1≤x≤100),如果队伍 i i i 提交了 x x x 次题 j j j,且均未通过。

  • .,如果队伍 i i i 没有提交题 j j j。

如果有多种可能的答案,任意输出一种即可。

请注意,在输入和输出中,?,+,-后总有一个空格。

输入输出样例 #1

输入 #1

复制代码
1 13
7 951
+ 1/6
? 3 4
+ 4/183
- 2
+ 3/217
.
.
.
+ 2/29
+ 1/91
.
+ 1/22
.

输出 #1

复制代码
Yes
+ 1/6
+ 2/263
+ 4/183
- 2
+ 3/217
.
.
.
+ 2/29
+ 1/91
.
+ 1/22
.

输入输出样例 #2

输入 #2

复制代码
6 2
1 100
.
? 3 4
2 100
+ 1/1
+ 1/2
0 0
- 5
- 6
2 480
? 100 100
? 100 100
2 480
? 99 100
? 100 100
1 2000
? 100 100
? 100 100

输出 #2

复制代码
No
No
Yes
- 5
- 6
Yes
+ 1/240
+ 1/240
No
Yes
+ 87/280
- 100

模拟

点、加号和减号原样输出。

解析+的x,y。n1++,t1+= 20 × ( x − 1 ) + y 20\times(x-1)+y 20×(x−1)+y

枚举带?的题的对错,不超过m道。故状态数不超过 2 m 2^m 2m。

令做对了n2题,最少用时t21,最多用时t22。

如果 n 1 + n 2 = = a 且 ( t 1 + t 21 ) ≥ b 且 ( t 1 + t 22 ) ≤ b n1+n2==a 且 (t1+t21) \geq b 且(t1+t22) \leq b n1+n2==a且(t1+t21)≥b且(t1+t22)≤b

计算t11:第 ( y − x ) + 1 (y-x)+1 (y−x)+1次于240分提交通过。

计算t12:第 y y y次于299分提交。

如果分配b

以t11为基础,多的时间如果超过20,则提交数增加。

提交次数到上限了,则延长提交时间。

如果还有剩余。返回冲突。

代码

核心代码

cpp 复制代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include<array>

#include <bitset>
using namespace std;

template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
	in >> pr.first >> pr.second;
	return in;
}

template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t);
	return in;
}

template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
	return in;
}

template<class T1, class T2, class T3, class T4, class T5, class T6, class T7 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4,T5,T6,T7>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t) >> get<5>(t) >> get<6>(t);
	return in;
}

template<class T = int>
vector<T> Read() {
	int n;
	cin >> n;
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}
template<class T = int>
vector<T> ReadNotNum() {
	vector<T> ret;
	T tmp;
	while (cin >> tmp) {
		ret.emplace_back(tmp);
		if ('\n' == cin.get()) { break; }
	}
	return ret;
}

template<class T = int>
vector<T> Read(int n) {
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

template<int N = 1'000'000>
class COutBuff
{
public:
	COutBuff() {
		m_p = puffer;
	}
	template<class T>
	void write(T x) {
		int num[28], sp = 0;
		if (x < 0)
			*m_p++ = '-', x = -x;

		if (!x)
			*m_p++ = 48;

		while (x)
			num[++sp] = x % 10, x /= 10;

		while (sp)
			*m_p++ = num[sp--] + 48;
		AuotToFile();
	}
	void writestr(const char* sz) {
		strcpy(m_p, sz);
		m_p += strlen(sz);
		AuotToFile();
	}
	inline void write(char ch)
	{
		*m_p++ = ch;
		AuotToFile();
	}
	inline void ToFile() {
		fwrite(puffer, 1, m_p - puffer, stdout);
		m_p = puffer;
	}
	~COutBuff() {
		ToFile();
	}
private:
	inline void AuotToFile() {
		if (m_p - puffer > N - 100) {
			ToFile();
		}
	}
	char  puffer[N], * m_p;
};

template<int N = 1'000'000>
class CInBuff
{
public:
	inline CInBuff() {}
	inline CInBuff<N>& operator>>(char& ch) {
		FileToBuf();
		while (('\r' == *S) || ('\n' == *S) || (' ' == *S)) { S++; }//忽略空格和回车
		ch = *S++;
		return *this;
	}
	inline CInBuff<N>& operator>>(int& val) {
		FileToBuf();
		int x(0), f(0);
		while (!isdigit(*S))
			f |= (*S++ == '-');
		while (isdigit(*S))
			x = (x << 1) + (x << 3) + (*S++ ^ 48);
		val = f ? -x : x; S++;//忽略空格换行		
		return *this;
	}
	inline CInBuff& operator>>(long long& val) {
		FileToBuf();
		long long x(0); int f(0);
		while (!isdigit(*S))
			f |= (*S++ == '-');
		while (isdigit(*S))
			x = (x << 1) + (x << 3) + (*S++ ^ 48);
		val = f ? -x : x; S++;//忽略空格换行
		return *this;
	}
	template<class T1, class T2>
	inline CInBuff& operator>>(pair<T1, T2>& val) {
		*this >> val.first >> val.second;
		return *this;
	}
	template<class T1, class T2, class T3>
	inline CInBuff& operator>>(tuple<T1, T2, T3>& val) {
		*this >> get<0>(val) >> get<1>(val) >> get<2>(val);
		return *this;
	}
	template<class T1, class T2, class T3, class T4>
	inline CInBuff& operator>>(tuple<T1, T2, T3, T4>& val) {
		*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);
		return *this;
	}
	template<class T = int>
	inline CInBuff& operator>>(vector<T>& val) {
		int n;
		*this >> n;
		val.resize(n);
		for (int i = 0; i < n; i++) {
			*this >> val[i];
		}
		return *this;
	}
	template<class T = int>
	vector<T> Read(int n) {
		vector<T> ret(n);
		for (int i = 0; i < n; i++) {
			*this >> ret[i];
		}
		return ret;
	}
	template<class T = int>
	vector<T> Read() {
		vector<T> ret;
		*this >> ret;
		return ret;
	}
private:
	inline void FileToBuf() {
		const int canRead = m_iWritePos - (S - buffer);
		if (canRead >= 100) { return; }
		if (m_bFinish) { return; }
		for (int i = 0; i < canRead; i++)
		{
			buffer[i] = S[i];//memcpy出错			
		}
		m_iWritePos = canRead;
		buffer[m_iWritePos] = 0;
		S = buffer;
		int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);
		if (readCnt <= 0) { m_bFinish = true; return; }
		m_iWritePos += readCnt;
		buffer[m_iWritePos] = 0;
		S = buffer;
	}
	int m_iWritePos = 0; bool m_bFinish = false;
	char buffer[N + 10], * S = buffer;
};

class Solution {
		public:
			vector<string> Ans(int rcnt,int time, vector<string>& strs) {
				int n1 = 0, t1 = 0;
				vector<tuple<int, int,int>> v;
				for (const auto& s : strs) {
					if ('+' == s[0]) {
						int pos1 = s.find('/');
						const int x = atoi(s.c_str() + 2);
						const int y = atoi(s.c_str() + pos1 + 1);
						n1++;
						t1 += (x - 1) * 20 + y;
					}
					else if ('?' == s[0]) {
						auto tmp = s.substr(2);
						const int pos = tmp.find(' ');
						const int x = atoi(tmp.c_str() );
						const int y = atoi(tmp.c_str() + pos + 1);
						v.emplace_back(y, y - x + 1,240);
					}
				}
				if (v.empty()) {
					if ((n1 != rcnt) || (time != t1)) { return {};	}
					return strs;
				}				
				const int M = 1 << v.size();
				for (int m = 0; m < M; m++)
				{
					int i = -1;
					int n2 = 0, t21 = 0, t22 = 0;
					for (const auto& [may, miy,tmp] : v) {
						i++;
						if ((1 << i) & m) { continue; }
						n2++;
						t21 += (miy - 1) * 20 + 240;
						t22 += (may - 1) * 20 + 299;
					}
					if ((n1 + n2 != rcnt)) { continue; }
					if ((time < t1 + t21) || (time > t1 + t22)) { continue; }
					int remain = time - t1 - t21;
					i = -1;
					for (auto& [may, miy, tmp] : v) {
						i++;
						if ((1 << i) & m) { continue; }
						const int i1 = min(may - miy, remain / 20);
						miy += i1; remain -= i1 * 20;
					}
					i = -1;
					for (auto& [may, miy, tmp] : v) {
						i++;
						if ((1 << i) & m) { continue; }
						const int i1 = min(59, remain);
						tmp += i1; remain -=i1;
					}
					vector<string> str2;
					i = -1;
					for (auto& [may, miy, tmp] : v) {
						i++;
						if ((1 << i) & m) { str2.emplace_back("- " + to_string(may)); continue; }
						str2.emplace_back("+ " + to_string(miy) +"/" + to_string(tmp));
					}
					for (int i = 0, j = 0; i < strs.size(); i++) {
						if ('?' == strs[i][0]) {
							strs[i] = str2[j++];
						}
					}
					return strs;
				}
				return {};
			}		
		};

int main() {
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG	
	ios::sync_with_stdio(0); cin.tie(nullptr);
	//CInBuff<> in; COutBuff<10'000'000> ob;
	int N,M,rcnt,time;
	cin >> N >> M ;
	char buf[1000] = { 0 };
	for (int i = 0; i < N; i++)
	{
		cin >> rcnt >> time;
		cin.getline(buf, 999);
		vector<string> strs;
		for (int j = 0; j < M; j++) {
			cin.getline(buf, 999);
			strs.emplace_back(buf);
		}
		auto res= Solution().Ans(rcnt,time,strs);
#ifdef _DEBUG	
		printf("rcnt=%d,time=%d", rcnt,time);
		Out(strs, ",strs=");
		//Out(lr, ",lr=");
#endif // DEBUG	
		if (res.empty()) {
			cout << "No" << "\n";
		}
		else {
			cout << "Yes" << "\n";
			for (const auto& i: res) {
				cout << i << "\n";
			}
		}		
	}
	return 0;
};

单元测试

cpp 复制代码
		int rcnt, time;
		vector<string> strs;
		void Check(int rcnt, int time, vector<string> strs) {
			int n1 = 0, t1 = 0;
			for (const auto& s : strs) {
				if ('+' == s[0]) {
					int pos1 = s.find('/');
					const int x = atoi(s.c_str() + 2);
					const int y = atoi(s.c_str() + pos1 + 1);
					n1++;
					t1 += (x - 1) * 20 + y;
				}
			}
			AssertEx(rcnt, n1);
			AssertEx(time, t1);
		}
		TEST_METHOD(TestMethod11)
		{
			rcnt = 7, time = 951, strs = { "+ 1/6","? 3 4","+ 4/183","- 2","+ 3/217",".",".",".","+ 2/29","+ 1/91",".","+ 1/22","."};
			auto res = Solution().Ans(rcnt,time, strs);
			Check(rcnt, time, res);
		}	
		TEST_METHOD(TestMethod12)
		{
			rcnt = 1, time = 100, strs = { ".","? 3 4" };
			auto res = Solution().Ans(rcnt, time, strs);
			AssertEx({}, res);
		}
		TEST_METHOD(TestMethod13)
		{
			rcnt = 2, time = 100, strs = { "+ 1/1","+ 1/2" };
			auto res = Solution().Ans(rcnt, time, strs);
			AssertEx({}, res);
		}
		TEST_METHOD(TestMethod14)
		{
			rcnt = 2, time = 480, strs = { "? 99 100","? 100 100" };
			auto res = Solution().Ans(rcnt, time, strs);
			AssertEx({}, res);
		}
		TEST_METHOD(TestMethod21)
		{
			rcnt = 0, time = 0, strs = { "- 5","- 6" };
			auto res = Solution().Ans(rcnt, time, strs);
			Check(rcnt, time, res);
		}
		TEST_METHOD(TestMethod22)
		{
			rcnt = 2, time = 480, strs = { "? 100 100","? 100 100" };
			auto res = Solution().Ans(rcnt, time, strs);
			Check(rcnt, time, res);
		}
		TEST_METHOD(TestMethod23)
		{
			rcnt = 1, time = 2000, strs = { "? 100 100","? 100 100" };
			auto res = Solution().Ans(rcnt, time, strs);
			Check(rcnt, time, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法 用**C++**实现。

相关推荐
Frank_refuel2 小时前
C++STL之set和map的接口使用介绍
数据库·c++·算法
java修仙传2 小时前
力扣hot100:跳跃游戏||
算法·leetcode·游戏
永远都不秃头的程序员(互关)2 小时前
【K-Means深度探索(十一)】K-Means VS 其他聚类算法:如何选择最合适的工具?
算法·kmeans·聚类
洛生&2 小时前
Nested Ranges Count
算法
老鼠只爱大米2 小时前
LeetCode经典算法面试题 #142:环形链表 II(哈希表、快慢指针等多种方法详细解析)
算法·leetcode·链表·快慢指针·floyd算法·环形链表
王老师青少年编程2 小时前
2024年6月GESP真题及题解(C++八级): 最远点对
c++·题解·真题·gesp·csp·八级·最远点对
数智工坊2 小时前
【操作系统-线程介绍】
linux·算法·ubuntu
小龙报2 小时前
【C语言进阶数据结构与算法】LeetCode27 && LeetCode88顺序表练习:1.移除元素 2.合并两个有序数组
c语言·开发语言·数据结构·c++·算法·链表·visual studio
炽烈小老头2 小时前
【每天学习一点算法 2026/01/21】倒二进制位
学习·算法