CDZSC_2022寒假个人训练赛21级(5)题解

  • 简单
    • F 模拟
    • G 模拟
    • I 数学
  • 中等
    • A 模拟
    • B 枚举
    • C 数学
  • 困难
    • D 模拟
    • E 贪心、构造、数据结构
    • H DP、矩阵快速幂

A Nearest Minimums CodeForces - 911A

题意

给你一个数组a,问你其中两个最小值的的最小距离是多少。

题解

两个循环,先找最小值,然后再找最小距离。

AC代码

int s[100005];
int main() {
	int n;
	scanf("%d", &n);
	int min = 1e9;
	for (int i = 0; i < n; i++) {
		scanf("%d", s + i);
		min = min < s[i] ? min : s[i];
	}
	int ans = 1e9,last=-1;
	for (int i = 0; i < n; i++) {
		if (s[i] == min) {
			if (last != -1) {
				ans = ans < i - last ? ans : i - last;
			}
			last = i;
		}
	}
	printf("%d\n", ans);

	return 0;
}

B Two Cakes CodeForces - 911B

题意

分蛋糕,有两种蛋糕分 n 份,满足如下条件:

  • 所有蛋糕都被分出去了
  • 一份中至少有一个蛋糕
  • 一份中不能有两种不同的蛋糕
    使每份,最小块数最大化,问最小块是多少。

题解

数据很小,枚举第一个蛋糕分几份,取最小值的最大值。

AC代码

int main() {
	int n,a,b;
	scanf("%d%d%d", &n,&a,&b);
	int ans = 0;
	for (int i = 1; i <n; i++)
		ans=max(ans,min(a/i,b/(n-i)));
	printf("%d\n", ans);
	return 0;
}

C Three Garlands CodeForces - 911C

题意

给你 3 个数 \(k_1,k_2,k_3\) 问你,\(\{i\in \{0,1,2,3...\} |x+i\cdot k_1,y+ i\cdot k_2,z+ i\cdot k_3\;\;\;\;x,y,z\in \{N,0\} \}\)能否覆盖正整数集合。

题解

很容易想到就只有以下4种解

  • 1 x x
  • 2 2 x
  • 3 3 3
  • 4 4 2

枚举判断下就好了

也很好理解,有1那表示那个为1的灯一直亮,肯定行,有两个2,这两个灯可以交替亮,也肯定行,3个3也是同理,4,4,2 的情况,两个4可以轮流吧2的空位补全,如下。
a为4,b为4,c为2
时间: 1 2 3 4
亮灯: c a c b

时间: 5 6 7 8
亮灯: c a c b
...

实际上这题都不用想,直接写个暴力程序,把小于5的情况都遍历一下,就知道所有解了。
(为什么小于5?,这不是就给你3个数字吗,保险点也可以跑大点,想想就知道不可能很大。)

AC代码

int main() {
	int a, b, c;
	scanf("%d%d%d", &a, &b, &c);

	if ((a==1)||(b==1)||(c==1)
		||(a == 2 && b == 2)
		|| (a == 2 && c == 2)
		|| (c == 2 && b == 2)
		|| (a == 3 && b == 3 && c == 3)
		|| (a == 2 && b == 4 && c == 4)
		|| (a == 4 && b == 2 && c == 4)
		|| (a == 4 && b == 4 && c == 2)
		)
		printf("YES\n");
	else printf("NO\n");

	return 0;
}

D Anton and Chess CodeForces - 734D

题意

Bishop 可以斜着走,Rook 可以垂直水平走,Queen 可以斜着走也可以垂直水平走。
但是不能越过其他棋子。求能否吃掉对方的 King。

题解

枚举 King 的八个方向的第一个棋子,看是否是能吃掉它的。
根据 King 的坐标把其他棋子分类,然后根据里 King 的距离排序,再判断。

AC代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>

#define s(x,y) sort(x.begin(),x.end(),y);


using namespace std;
typedef long long ll;
const ll N=5e5+5;

struct node{
	char c;
	int x,y;
}s[N];

vector<node>l,r,d,u,ld,lu,rd,ru;

bool cmpl(node a,node b){
	return a.y>b.y;
}
bool cmpr(node a,node b){
	return a.y<b.y;
}
bool cmpu(node a,node b){
	return a.x>b.x;
}
bool cmpd(node a,node b){
	return a.x<b.x;
}
bool cmpru(node a,node b){
	return a.x<b.x;
}
bool cmpld(node a,node b){
	return a.x>b.x;
}
bool cmprd(node a,node b){
	return a.x<b.x;
}
bool cmplu(node a,node b){
	return a.x>b.x;
}


int main(){
	int n,x,y,a,b;
	char c;
	int flag=0;
	scanf("%d%d%d",&n,&x,&y);

	for(int i=0;i<n;i++){
		node tmp;
		scanf("%s%d%d",&tmp.c,&tmp.x,&tmp.y);
		

		if(tmp.x==x){
			if(tmp.y>y)r.push_back(tmp);
			else l.push_back(tmp);
		}
		else if(tmp.y==y){
			if(tmp.x>x)d.push_back(tmp);
			else u.push_back(tmp);
		}
		else if(tmp.x+tmp.y==x+y){
			if(tmp.x>x)rd.push_back(tmp);
			else lu.push_back(tmp);
		}
		else if(abs(tmp.x-tmp.y)==abs(x-y)){
			if(tmp.x>x)rd.push_back(tmp);
			else lu.push_back(tmp);
		}
	}
	s(l,cmpl);
	s(r,cmpr);
	s(d,cmpd);
	s(u,cmpu);
	s(lu,cmplu);
	s(ld,cmpld);
	s(ru,cmpru);
	s(rd,cmprd);

	if(l.size()&&(l[0].c=='R'||l[0].c=='Q'))flag=1;
	if(r.size()&&(r[0].c=='R'||r[0].c=='Q'))flag=1;
	if(u.size()&&(u[0].c=='R'||u[0].c=='Q'))flag=1;
	if(d.size()&&(d[0].c=='R'||d[0].c=='Q'))flag=1;
	if(lu.size()&&(lu[0].c=='B'||lu[0].c=='Q'))flag=1;
	if(ld.size()&&(ld[0].c=='B'||ld[0].c=='Q'))flag=1;
	if(ru.size()&&(ru[0].c=='B'||ru[0].c=='Q'))flag=1;
	if(rd.size()&&(rd[0].c=='B'||rd[0].c=='Q'))flag=1;

	if(flag)printf("YES\n");
	else printf("NO\n");
	scanf(" ");
}

E Misha and Forest CodeForces - 501C

题意

定义一个森林为非有向无环图(没有重边与环)给出\(n(n\le2^{16})\)个节点的两个信息,第一个为该节点有几个与其相邻的节点,第二个为与其相邻的节点的编号的异或值。输出森林有几条边与这些边的具体信息。(可以以任意顺序输出,数据保证有解)

tips:节点从0开始编号

题解

既然是一个非有向无环图,那必存在至少 2 个节点只有一条边与其相连,所以我们可以先找出这些点,然后记录下这些边,把点删除,这时我们得到了一张新的图,这新图中又会出现只有一条边与其相连的点(就是之前只有两条边相连的点),以此往复,直到没有新的点出现。

(还有没有连边的点,但我们要求的是边,所以可以完全不管那些点)

AC代码

int deg[N],s[N];
int l[N];
int a[N],b[N];
vector<int>e[N];

int main(){
	int n,m=0;
	int cnt=0;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d%d",&deg[i],&s[i]);
		if(deg[i]==1){
			l[cnt++]=i;;
		}
	}

	for(int i=0;i<cnt;i++){
		int x=s[l[i]];
		if(deg[l[i]]!=1)continue;
		a[m]=l[i];
		b[m++]=x;
		deg[x]--;
		s[x]^=l[i];
		if(deg[x]==1){
			l[cnt++]=x;
		}
	}
	
	printf("%d\n",m);
	for(int i=0;i<m;i++){
		printf("%d %d\n",a[i],b[i]);
	}

    return 0;
}

F Police Recruits CodeForces - 427A

题意

输入 n 个整数。如果整数为 -1,则表示发生了犯罪。如果整数为正数,则这个数表示招募的警官人数。一次最多招募 10 名警官。
一个警察只能解决一个案件,如果犯罪出现的时候,没有警察,那那个犯罪对应的案件就不会被解决。
问,未处理的犯罪数量。

题解

简单模拟

AC代码

int main() {
	int n, x,sum=0,ans=0;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%d", &x);
		if (x == -1) {
			if (sum == 0)ans++;
			else sum--;
		}
		else sum+=x;
	}
	printf("%d\n", ans);
	return 0;
}


G Suffix Three CodeForces - 1281A

题意

给定 n 个字符串,对于每个字符串:

  • 若它以 po 结尾,输出 FILIPINO
  • 若它以 desu 或 masu 结尾,输出 JAPANESE
  • 若它以 mnida 结尾,输出 KOREAN
    保证所给的字符串一定满足以上的三种情况之一。

题解

简单模拟

AC代码

int n;
char s[1003];
int main(){
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s",s+1); 
        n=strlen(s+1);
		if(n>=2 
            && s[n-1]=='p' 
            && s[n]=='o') 
            printf("FILIPINO");
		else if(n>=5 
            && s[n-4]=='m' 
            && s[n-3]=='n' 
            && s[n-2]=='i' 
            && s[n-1]=='d' 
            && s[n]=='a') 
            printf("KOREAN");
		else printf("JAPANESE");
	}
	return 0;
}

H 可乐 黑暗爆炸 - 4887

题意

中文题,应该不会读错吧?

题解

正解矩阵快速幂优化dp,我不会(我不是dp选手,想学的可以问你们璐聃师兄。
我乱搞出来的。(可能算dp吧
我们可以把所有的情况看成一颗树,根为1,爆炸为0,对应的节点是对应的数字,树深度是时间,然后就可以构造出一颗状态树,我们要求的实际上是树的叶节点数。
所以我们只要遍历一遍这颗树就能知道答案了。但那样复杂度太高了,所以我们可以想办法化简归并一些操作。
仔细观察就会发现,某个数字节点的分支是相同的,比如样例中,节点1的分支固定为3个,0,1,2,即自爆,不动,去其他节点。节点2的分支为4个,0,1,2,3,他多了一个去3号节点。所以节点的分支等于,2+边数,这样我们只要知道这个点是什么节点就可以知道他有多少个分支了。
在同一深度(时间)中的所有同数值节点实际上完全没有区别,我们不用一个个去计算他,我们可以和在一起计算,比如样例中,在第二个时刻,总共有2种操作正在1上,2种在2上,一种在3上。因为,第一步,1到2,所以,这时1有1个,2有一个,第二步,1再到2,2到3和1,这时,1就有2个,2有2个,3有1个。
我们知道了节点1有2个,节点2有2个,节点3有一个,根据上面的推论,我们就知道,下一层总共有,23+24+3=17 个节点。
总体逻辑就是上面那边,一步一步去扩散状态的数量。然后计数。

AC代码

const int mod=2017;
int en[31];//点的边数
int tmp[31];//临时数组,防止加状态数的影响
int sta[31];//状态数,即这个时间在这个节点上的状态的数量
int e[31][100];
int s[31];
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d%d", &u, &v);
		e[u][s[u]++] = v;
		e[v][s[v]++] = u;
		en[u]++;
		en[v]++;
	}
	sta[1] = 1;
	int t;
	scanf("%d", &t);
	int ans = 0;
	for (int i = 0; i < t - 1; i++) {

		for (int j = 1; j <= n; j++) {
			ans = (ans + sta[j] ) % mod;//每一个节点都有爆炸选项,所以ans要加上所有节点数
			for (int k = 0; k < s[j]; k++) {
				int x = e[j][k];
				tmp[x] = (tmp[x] + sta[j]) % mod;//节点扩散
			}
		}
		for (int j = 1; j <= n; j++) {
			sta[j] = (sta[j] + tmp[j]) % mod;
			tmp[j] = 0;
		}
	}
	for (int i = 1; i <= n; i++) {
		ans = (ans + (en[i] + 2) % mod*sta[i] % mod) % mod;
	}
	printf("%d\n", ans);


	return 0;
}

I Odd Divisor CodeForces - 1475A

题意

给你一个整数n。检查n是否有一个大于1的奇数除数(是否存在这样一个数x(x>1),n可以被x整除,x是奇数)。

题解

检查是不是2的幂

AC代码

//方法一
int main() {
	ll n,t;
	scanf("%lld", &t);
	while (t--) {
		int flag = 0;
		scanf("%lld", &n);
		while (n % 2 == 0)n /= 2;
		printf("%s\n",n!=1 ? "YES" : "NO");
	}
    return 0;
}
//方法二
int main() {
	ll n,t;
	scanf("%lld", &t);
	while (t--) {
		int flag = 0;
		scanf("%lld", &n);
		
		printf("%s\n",n&(n-1)? "YES" : "NO");
	}
    return 0;
}
posted @ 2022-01-29 17:02  _comet  阅读(120)  评论(0编辑  收藏  举报