T1 红色警戒

难度:主要难点在于读题。

算法:模拟。

子任务 113030 分):由于所有桥的耐久度都相同,所以炸掉谁都一样,本来直接输出任何一座桥的耐久度都可以,但要注意耐久度为 00 也要一辆卡车,所以至少要输出 11

子任务 223030 分):此时保证了数据从小到大排序,所以第一座桥的耐久度是最低的,输出 max(a[1] ,1) 即可。

子任务 334040 分):此时要找到九座桥的最小值,再来按照前面的做法即可。

C++ 代码

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int a, ans = 1001;
    cin >> a; if (a < ans) ans = a;
    cin >> a; if (a < ans) ans = a;
    cin >> a; if (a < ans) ans = a;
    cin >> a; if (a < ans) ans = a;
    cin >> a; if (a < ans) ans = a;
    cin >> a; if (a < ans) ans = a;
    cin >> a; if (a < ans) ans = a;
    cin >> a; if (a < ans) ans = a;
    cin >> a; if (a < ans) ans = a;
    if(ans == 0) ans = 1;
    
    cout << ans << endl;
    
    return 0;
}

T2 有趣的&运算

难度:需要一些数学思维,要能推理出只要拆开了就只会让结果变大或者保持不变,因此答案就是只分为一个区间 [1,n][1,n],所有数进行与运算的结果。

算法:数学。

子任务 113030 分):只有两个数,答案只有两种情况:a[1] + a[2] 或者 a[1] & a[2],输出其中较小的即可。

子任务 223030 分):nn 非常小,可以暴力枚举所有的划分方案,但实际上暴力枚举所有划分方案的代码挺难写。

子任务 334040 分):求所有数进行与运算的结果,需要注意和求和的初始化为 00 不同,与运算的初始化比较复杂。你可以初始化为第一个数或者初始化为补码为全 11 的 1−1

做法1

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n, ai, ans;
    cin >> n;
    for (int i = 1; i <= n; i ++ )
    {
    	cin >> ai;
    	if (i == 1) ans = ai;
    	else ans = ans & ai;
    }
    
    cout << ans << endl;
    
    return 0;
}

做法2

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n, ai, ans = -1;
    cin >> n;
    for (int i = 1; i <= n; i ++ )
    {
    	cin >> ai;
    	ans = ans & ai;
    }
    
    cout << ans << endl;
    
    return 0;
}

T3 比赛的获奖规则

难度:结构体排序的模拟题。

算法:排序,模拟。

子任务 113030 分):此时省去了排序的步骤,可以先算出有效队伍数量,然后算出需要输出的排名,最后输出对应的排名即可。

子任务 223030 分):最后输出的就是排在前面金牌区的选手,耐心写完排序后会简单很多。

子任务 334040 分):题目怎么说的就怎么排序就好,我的代码中有一些特殊处理,我把打星队伍的排名挪到了最低,这样最后输出某个排名区间的队伍会方便一点。

C++ 代码

#include<bits/stdc++.h>
using namespace std;

int n;
struct Team
{
    string school, team;
    int solved, tim;
    bool flag; // 是否打星
}a[200000 + 5];

bool cmp(Team x, Team y)
{
	if (x.flag == false && y.flag == false) return x.school < y.school;
	if (x.flag == false || y.flag == false) return x.flag > y.flag;
	if (x.solved != y.solved) return x.solved > y.solved;
	return x.tim < y.tim;
}

int main()
{
    cin >> n;
    int A = 0, J, Y, T;
    for (int i = 1; i <= n; i ++ )
    {
    	cin >> a[i].school >> a[i].team >> a[i].solved >> a[i].tim;
    	a[i].flag = (a[i].solved > 0) && (a[i].team.back() != '*');
    	A += a[i].flag;
    }
    J = A * 10 / 100 + (A * 10 % 100 > 0);
    Y = A * 30 / 100 + (A * 30 % 100 > 0) - J;
    T = A * 60 / 100 + (A * 60 % 100 > 0) - Y - J;
    sort(a + 1, a + n + 1, cmp);
    string s;
    cin >> s;
    
    int l, r;
    if (s == "gold") l = 1, r = J;
    else if (s == "silver") l = J + 1, r = J + Y;
    else l = J + Y + 1, r = J + Y + T;
    
    cout << (r - l + 1) << endl;
    for (int i = l; i <= r; i ++ )
    	cout << a[i].school << " " << a[i].team << " " << a[i].solved << " " << a[i].tim << endl;
    
    return 0;
}

T4 真的是毒瘤题吗

难度:比较麻烦的二维数组上的模拟,满分需要一个小技巧,求出初始值后每次只修改变动带来的影响。

算法:枚举,模拟。

子任务 113030 分):只有操作 22,整个数组没有修改过,按照题目模拟求出所有单词出现的次数即可。

子任务 223030 分):数据范围很小,可以纯枚举做所有操作。

子任务 334040 分):数据范围比较大,每次查询不能纯暴力枚举了。当算出了初始的所有单词以及对应的出现次数后,容易发现每次只修改了一个位置,因此最多影响了和这个位置有关的单词。可以先去掉之前所有相关的单词,然后新增新产生的单词即可。这里我没有偷懒使用 map 存所有单词出现次数,而是直接采用了一个四维数组。然后我写了挺多辅助函数,来让我的主函数更简洁。当时间复杂度没有问题的时候,我建议同学们也可以采用这样的方法,不用图快,把每一块做清楚能省掉更多调试的时间。

C++ 代码

#include<bits/stdc++.h>
using namespace std;

int n, m;
char g[305][305];
int cnt[30][30][30][30];
int dx[] = {0, 1, 0, 1}, dy[] = {0, 0, 1, 1};

// 行数、列数、方向(竖1、横2、右下斜着3)、长度
string getS(int x, int y, int fx, int len)
{
    if (x < 1 || y < 1) return "";
    if (fx == 1 && x + len - 1 > n) return "";
    if (fx == 2 && y + len - 1 > m) return "";
    if (fx == 3 && (x + len - 1 > n || y + len - 1 > m)) return "";
    string res = "";
    for (int i = 0; i < len; i ++ )
    {
    	res += g[x][y];
    	x += dx[fx];
    	y += dy[fx];
    }
    return res;
}

// s 的出现次数加上 num
void cal(string s, int num)
{
	int a[4] = {0, 0, 0, 0};
	for (int i = 0; i < s.size(); i ++ )
		a[i] = s[i] - 'a' + 1;
	cnt[a[0]][a[1]][a[2]][a[3]] += num;
}

// 返回 s 的出现次数
int getCnt(string s)
{
	int a[4] = {0, 0, 0, 0};
	for (int i = 0; i < s.size(); i ++ )
		a[i] = s[i] - 'a' + 1;
	return cnt[a[0]][a[1]][a[2]][a[3]];
}

// 把 (x,y) 相关的单词数量增加 t
void change(int x, int y, int t)
{
	for (int len = 1; len <= 4; len ++ )
	{
		cal(getS(x, y, 1, len), t);
		cal(getS(x, y, 2, len), t);
		cal(getS(x, y, 3, len), t);
	}
	for (int len = 2; len <= 4; len ++ )
	{
		cal(getS(x - 1, y, 1, len), t);
		cal(getS(x, y - 1, 2, len), t);
		cal(getS(x - 1, y - 1, 3, len), t);
	}
	for (int len = 3; len <= 4; len ++ )
	{
		cal(getS(x - 2, y, 1, len), t);
		cal(getS(x, y - 2, 2, len), t);
		cal(getS(x - 2, y - 2, 3, len), t);
	}
	for (int len = 4; len <= 4; len ++ )
	{
		cal(getS(x - 3, y, 1, len), t);
		cal(getS(x, y - 3, 2, len), t);
		cal(getS(x - 3, y - 3, 3, len), t);
	}
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ )
    	for (int j = 1; j <= m; j ++ )
    		cin >> g[i][j];
    
    for (int i = 1; i <= n; i ++ )
    	for (int j = 1; j <= m; j ++ )
    		for (int len = 1; len <= 4; len ++ )
    		{
    			cal(getS(i, j, 1, len), 1);
    			cal(getS(i, j, 2, len), 1);
    			cal(getS(i, j, 3, len), 1);
    		}
    int q;
    cin >> q;
    while (q -- )
	{
		int op;
		cin >> op;
		if (op == 1)
		{
			int x, y;
			char c;
			cin >> x >> y >> c;
			change(x, y, -1);
			g[x][y] = c;
			change(x, y, 1);
		}
		if (op == 2)
		{
			string s;
			cin >> s;
			cout << getCnt(s) << endl;
		}
	}
    
    return 0;
}

0 comments

No comments so far...