[第六场]再次爆炸记

T1

解题思路

按照题目思路判断即可,有一些坑,后面判概率是要令总和严格大于21,并且概率要严格大于50....

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
int n,a[100005],sum;
int vis[105],tot;
int main(){
	scanf ("%d",&n);
	for (int i = 1;i <= n;i ++){
		scanf ("%d",&a[i]);
		sum += a[i];
		vis[a[i]] ++;
	}
	if (21 - sum <= 0)
		printf("DOSTA\n");
	else {
		for (int i = 2;i <= 11;i ++){
			if (i == 10){
				if (21 - sum - i < 0)
					tot += 16 - vis[i];
			}
			else if (21 - sum - i < 0)
				tot += 4 - vis[i];
		}
		if (tot * 2 > (52 - n))
			printf("DOSTA\n");
		else 
			printf("VUCI\n");
	}
}

T2

题目描述

小时候GM很喜欢玩俄罗斯方块,游戏里有五种不同样式的方块,分别给它们编号,如下图:

avatar

现给你一个N行M列的矩阵,矩阵中.代表空白,相同相邻字母代表同一种方块。请你输出矩阵中五种方块的个数。

输入
第一行输入包含整数N,M(1≤N,M≤10)。
后面N行,每行M列,输入矩阵。

输出
五行,每行1个整数,代表对应方块的个数。

分数分布
对于20%的数据,只会出现第一种方块。
对于20%的数据,只会出现前两种方块。
对于20%的数据,只会出现前三种方块。
对于20%的数据,只会出现前四种方块。

 


样例输入1
4 5
aaaa.
.bb..
.bbxx
...xx
样例输出1
2
1
0
0
0

样例输入2
4 5
.aab.
aabb.
.cbaa
cccaa
样例输出2
1
0
1
1
1

样例输入3
5 7
.c.....
ccdddd.
caabbcc
aabbacc
...aaa.
样例输出3
1
1
2
1
1

解题思路

五种类型的这玩意,一共只有十二种可能,你可以枚举出所有,dfs找即可。其中发现,仅仅只有3号(1个)与5号(4个全部)有回溯,其余都是一遍搜到底。于是我们可以判断是否回溯,然后再来打表。反正我是这样做的

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,turn[105],mov1[5] = {0,1,-1,0,0},mov2[5] = {0,0,0,1,-1},tot,num[15];
char mase[15][15];
bool vis[15][15],flag;
void check(){
	if (turn[1] == 1 && turn[2] == 3 && turn[3] == 2){
		num[1] ++;
		return ;
	}
	if (turn[1] == turn[2] && turn[2] == turn[3]){
		num[2] ++;
		return ;
	}
	if ((turn[1] == 1 && turn[2] == 3 && turn[3] == 1) || (turn[1] == 1 && turn[2] == 4 && turn[3] == 3)){
		num[3] ++;
		return ;
	}
	if (flag){
		num[5] ++;
		return ;
	}
	if ((turn[1] == 1 && turn[2] == 4 && turn[3] == 1) || (turn[1] == 3 && turn[2] == 1 && turn[3] == 3)){
		num[4]++;
		return;
	}
}
void dfs(int x,int y,char c){
	vis[x][y] = 1;
	bool flag1 = 0;
	for (int i = 1;i <= 4;i ++){
		int tox = x + mov1[i];
		int toy = y + mov2[i];
		if (mase[tox][toy] == c && !vis[tox][toy]){
			if (flag1)
				flag = 1;
			flag1 = 1;
			turn[++ tot] = i;
			dfs(tox,toy,c);
		}
	}
}
int main(){
	//freopen("tetris.in","r",stdin);
//	freopen("tetris.out","w",stdout);
	scanf ("%d%d",&n,&m);
	for (int i = 1;i <= n;i ++){
		scanf ("\n");
		for (int j = 1;j <= m;j ++){
			scanf ("%c",&mase[i][j]);
		}
	}
	for (int i = 1;i <= n;i ++){
		for (int j = 1;j <= m;j ++){
			if (mase[i][j] != '.' && !vis[i][j]){
				flag = 0;
				tot = 0;
				dfs(i,j,mase[i][j]);
				check();
			}
		}
	}
	for (int i = 1;i <= 5;i ++)
		printf("%d\n",num[i]);
}

T3

题目描述

如果一个用户A的密码内含有另一个用户B的密码,那么A用户就可以登录B用户的账号。问有多少对这样的用户存在,使得前者可以登录后者的账号。

输入
第一行输入包含整数N(1≤N≤20000),表示用户数量。
后面N行,每行一个字符串,表示这个用户的密码,每个串不超过10个小写字母。

输出
输出一个整数。表示满足母子密码的对数总数。

分数分布
对于40%的数据,1≤N≤2000。

样例输入1
3
aaa
aa
abb
样例输出1
1


样例输入2
3
x
x
xy
样例输出2
4

样例输入3
5
mir
mirta
ta
ir
t
样例输出3
6

解题思路

考场乱开数组,导致原地爆炸,本来AC的我顿时少了不少分。

暴力过的,时间复杂度没有问题,关键是空间(毕竟64M)。

但字符串数据并不多,并且每一个长度仅为10,空间并不会炸。

我启用map,读入一个便累加它的所有子串。嗯,很暴力。

但其中会有一些重复累加的情况,嗯,再暴力开一个map。统计即可,很舒服。

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstring>
#include<map>
#include<cmath>
using namespace std;
int n;
map<string,int>mp;
long long ans;
char s[20005][105];//f**k
string str;
int main(){
	//freopen("lozinke.in","r",stdin);
//	freopen("lozinke.out","w",stdout);
	scanf ("%d",&n);
	for (int i = 1;i <= n;i ++){
		scanf ("%s",s[i]);
		int len = strlen(s[i]);
		str = "";
		for (int j = 0;j < len;j ++)
			str += s[i][j];
		len = str.size();
		map<string,bool>mp1;
		for (int j = 0;j < len;j ++){
			string str1 = "";
			for (int k = j;k < len;k ++){
				str1 += str[k];
				if (!mp1[str1]){
					mp1[str1] = 1;
					mp[str1] ++;
				}
			}
		}
	}
	for (int i = 1;i <= n;i ++){
		int len = strlen(s[i]);
		str = "";
		for (int j = 0;j < len;j ++)
			str += s[i][j];
		if (mp[str])
			ans += mp[str] - 1;
	}
	printf("%lld\n",ans);
}

T4

题目描述

冰球比赛,一队共N人(包括上场队员和替补队员),比赛时间共M分钟,每个队员有贡献值K和耐力值I两个属性,不限制换人次数,但同一个队员不能在当前上场后同一时刻又下场(你不觉得很无聊吗)
场上队员的贡献度 = 贡献值K × 上场时间X;X可以是多段上场时间。
问教练怎么安排6名主力队员?以及什么时间谁替换谁?才能使得全场总贡献值最大。

输入
输入的第一行包含正整数M和N,比赛的时间在M分钟内,参加的队员数量N。
以下N行每行包含两个正整数,K和I,表示球员的贡献和耐力。
玩家的编号从1到N,按照输入的顺序(第一个队员的编号是1,第二个是2,以此类推)。

输出
输出的第一行必须包含来自任务的最大可能Z。
第二行输出必须包含6个数字(空格隔开),即开始游戏的6个队员的编号。
第三行输出换人次数T,不能超过3*N。
最后输出T行,每行3个数,X(1≤X < M),A和B,其中X是替补队员加入比赛的时刻,A是退出比赛,进入板凳席的球员编号,B是将加入比赛的球员的编号。允许在同一分钟内进行多次替换。
如果存在多个解决方案,则输出任何。

分数分布
对于100%的数据:1≤I≤M≤500000,6≤N≤500000,1≤K≤100000。

 

样例输入1
200 6
3 200
4 200
5 200
6 200
7 200
8 200
样例输出1
6600
1 2 3 4 5 6
0

样例输入2
9 9
10 3
9 3
13 9
5 3
15 9
100 9
3 6
2 6
1 6
样例输出2
1260
1 2 3 4 5 6
3
3 1 7
3 2 8
3 4 9
样例输入3
3 9
100 3
100 3
100 3
100 3
100 2
100 1
50 1
30 2
1 1
样例输出3
1610
1 2 3 4 5 6
2
1 6 8
2 5 7

解题思路

考试当时便不会,在哪里一直试怎么排序。

正解玄学贪心,好像只有老师A了。

T5

题目描述
有一辆车上有n个小孩,年龄为1~n,然后q个询问,M X A代表在第X站时年龄为A的小孩会下车,D Y B代表询问年龄大于等于B且在第Y站(包含第Y站)以前下车的年龄最小的小孩,如果不存在,则输出-1。

输入
输入的第一行包含正整数N和Q,孩子的数量和询问的数量。
接下来Q行,每行3个值,第一个值为M或者D,询问有两种分别用M和D表示,M表示下车操作,D表示询问
如果是M X A,那么三个值的含义是:M X A代表在第X站时年龄为A的小孩会下车
如果是D Y B,代表询问年龄大于等于B且在第Y站(包含第Y站)以前下车的年龄最小的小孩,如果不存在,则输出-1。
所有询问都对应着不同的孩子,输入中至少有一行是询问的问题。

输出
对于每个询问的问题,输出答案。如果没有答案,输出-1。

分数分布
对于100%的数据:2≤N,Q≤200000,1≤X,Y≤1,000,000,000,1≤A,B≤N。

样例输入1
3 4
M 10 3
M 5 1
D 20 2
D 5 1

样例输出1
3
1

样例输入2
10 10
M 20 10
D 1 9
M 2 3
D 17 10
M 20 2
D 8 2
M 40 1
D 25 2
M 33 9
D 37 9
样例输出2
-1
-1
3
2
9

解题思路

考试还想用线段树,树状数组什么的,还打了离散化,树状数组都写好了。然而后面发现并不能(好像又可以?)。于是开始暴力。暴力的分数很震惊。感到惊异...

结果正解线段树板题。

由于年龄很小,我们用它作为线段树的下标(然后考试就没想到)。然后我们遇到查询,仅需查询B到N区间中车站是否Y,返回那个下标。最后加个剪枝:在前面区间搜到答案便不用管后面。感觉还真挺简单。其实就是改变下标这一个点。

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstring>
#include<map>
#include<cmath>
using namespace std;
struct node{
	int l,r,minn;
}tree[8000005];
int n,q,cnt,a,b,ans;
char x;
void build (int i,int l,int r){
	tree[i].l = l,tree[i].r = r;
	tree[i].minn = 0x3f3f3f3f;
	if (l == r)
		return ;
	int mid = (l + r) / 2;
	build(i * 2,l,mid);
	build (i * 2 + 1,mid + 1,r);
}
void insert(int i){
	if (tree[i].r < b || tree[i].l > b)
		return ;
	if (tree[i].l == b && tree[i].r == b){
		tree[i].minn = a;
		return ;
	}
	insert(i * 2);
	insert(i * 2 + 1);
	tree[i].minn = min(tree[i * 2].minn,tree[i * 2 + 1].minn);
}
int find(int i){
	if (tree[i].minn > a)
		return 0x3f3f3f3f;
	if (tree[i].l > n || tree[i].r < b)
		return 0x3f3f3f3f;
	if (tree[i].l == tree[i].r)
		return tree[i].l;
	int ret = 0x3f3f3f3f;
	ret = min(ret,find(i * 2));
	if (ret != 0x3f3f3f3f)
		return ret;
	else 
		return min(ret,find(i * 2 + 1));
}
void solve(int i){
	if (b <= tree[i].l){
		ans = find(i);
		return ;
	}
	if (tree[i].r < b)
		return ;
	solve(i * 2);
	if (ans != 0x3f3f3f3f)
		return ;
	solve(i * 2 + 1);
}
int main(){
	scanf ("%d%d",&n,&q);
	build (1,1,n);
	for (int i = 1;i <= q;i ++){
		scanf ("\n");
		scanf ("%c",&x);
		scanf ("%d%d",&a,&b);
		if (x == 'M')
			insert(1);
		else{
			int ans = 0x3f3f3f3f;
			ans = find(1);
			printf("%d\n",ans == 0x3f3f3f3f?-1:ans);
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值