Codeforces Round #634 (Div. 3)(A~F)题解

A.Candies and Two Sisters

题意:
n n n分为两个数 a a a, b b b,满足 a > b a>b a>b a + b = n a+b=n a+b=n
题解:
n n n对半分, n n n为偶数答案为 n / 2 − 1 n/2-1 n/21,奇数答案为 n / 2 n/2 n/2;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,n;
void solve(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		if(n%2==0) n=n/2-1;
		else n/=2;
		printf("%d\n",max(0,n));
	}
}
int main(void)
{
	solve();
	return 0;
 } 

B.Construct the String

题意:
给出三个数 n , a , b n,a,b n,a,b.
让你构造出一个长度为 n n n的字符串,该字符串满足每个长度为 a a a的字符串都有 b b b个不相同的字母
题解:
首先构造出开始的第一个合法的子字符串.
比如现在 n , a , b n,a,b n,a,b 7 , 5 , 3 7,5,3 7,5,3.
我构造出第一个子字符串为 a , b , c , a , a a,b,c,a,a a,b,c,a,a
然后遍历下一个子字符串,由于第二个字符串的前 n − 1 n-1 n1个已经确定,所以第 n n n个直接暴力求出即可.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e3+5;
int t,n,a,b,countt[27];
char s[MAX];
void solve(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&n,&a,&b);
		for(int i=1;i<=b;++i) s[i]='a'+(i-1);
		for(int i=b+1;i<=a;++i) s[i]='a';
		for(int i=2;i<=n-a+1;++i){
			memset(countt,0,sizeof(countt));
			for(int j=0;j<a-1;++j)
				countt[s[i+j]-'a']++;
			int num=0;
			char ch,sh;
			for(int j=0;j<=25;++j){
				if(countt[j]!=0) ++num,ch=j+'a';
				else sh=j+'a';
			}
			if(num==b) s[i+a-1]=ch;
			else s[i+a-1]=sh;
		}
		for(int i=1;i<=n;++i) printf("%c",s[i]);
		printf("\n");
	}
}
int main(void)
{
	solve();
	return 0;
 } 

C.Two Teams Composing

题意:
给你一个长度为 n n n的数组,让你从中挑选出一些数组成两个新的数组.
第一个数组要求两两不同,第二个数组要求全部相同
且两个数组的长度要一样
题解:
首先算出 n u m 1 , n u m 2 num1,num2 num1,num2.
n u m 1 num1 num1为一共有多少个不同的数字
n u m 2 num2 num2为相同的数字的最大值.

  1. n u m 1 − 1 > = n u m 2 num1-1>=num2 num11>=num2时:
    第二个数组的长度就是 n u m 2 num2 num2,第一个数组必定能取到 n u m 2 num2 num2,因为 n u m 1 − 1 > = n u m 2 num1-1>=num2 num11>=num2
  2. n u m 1 = = n u m 2 num1==num2 num1==num2时:
    答案为 n u m 2 − 1 num2-1 num21,因为第一个数组长度为 n u m 1 num1 num1的话就必须会取到相同的数字最多的那个数,那么第二个数组的长度就只能为 n u m 2 − 1 num2-1 num21.所以答案为 n u m 2 − 1 num2-1 num21
  3. n u m 1 < n u m 2 num1<num2 num1<num2
    显然答案为 n u m 1 num1 num1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5+5;
int t,n,countt[MAX],num1=0,num2=0;
void solve(){
	scanf("%d",&t);
	while(t--){
		num1=num2=0;
		scanf("%d",&n);
		for(int i=1;i<=n;++i) countt[i]=0;
		for(int i=1;i<=n;++i){
			int num;
			scanf("%d",&num);
			if(countt[num]==0){
				++num1;
				++countt[num];
				num2=max(1,num2);
			}
			else{
				++countt[num];
				num2=max(num2,countt[num]);
			}
		}
		if(num1>num2) printf("%d\n",num2);
		else if(num1==num2) printf("%d\n",max(0,num2-1));
		else printf("%d\n",num1);
	}
}
int main(void)
{
	solve();
	return 0;
 } 

D.Anti-Sudoku

题意:
给你一个 9 ∗ 9 9*9 99的数独,最多只能改9个数,输出一个反数独.
反数独定义为:
该字段中的任何数都在 [ 1 , 9 ] [1,9] [1,9]范围内;
每行包含至少两个相等的元素;
每一列至少包含两个相等的元素;
每个 3 × 3 3×3 3×3块包含至少两个相等的元素。

题解:
没什么可说的,直接把所有的2换成1就行了.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5+5;
int t;
char s[15][15];
void solve(){
	scanf("%d",&t);
	while(t--){
		for(int i=1;i<=9;++i) scanf("%s",s[i]+1);
		for(int i=1;i<=9;++i){
			for(int j=1;j<=9;++j)
				printf("%c",s[i][j]=='2'?'1':s[i][j]);
			printf("\n");
		}
	}
}
int main(void)
{
	solve();
	return 0;
 } 

E1&E2.Three Blocks Palindrome

题意:
给你一个长度为n的数组,让你找出一个长度最大的子序列,满足如下形式
在这里插入图片描述
题解:
由于 a i ai ai的大小只有 200 200 200.
对于两边的 a a a的数值,我们可以直接枚举.
然后枚举 a a a的长度,假如说枚举的长度为 j j j(一边的长度),那么肯定选取的是最左边的 j j j个和最右边的 j j j个,这样最优解一定包含在内.
然后再枚举中间的 b b b,处理 b b b的话记一个前缀和就好了.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5+5;
int t,n,a[MAX],countt[205][MAX],ans=0;
vector<int> list1[205];
void solve(){
	scanf("%d",&t);
	while(t--){
		ans=0;
		scanf("%d",&n);
		for(int i=1;i<=200;++i) list1[i].clear();
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
			list1[a[i]].push_back(i);
			++countt[a[i]][i];
			for(int j=1;j<=200;++j) countt[j][i]+=countt[j][i-1];
		}
		for(int i=1;i<=200;++i){
			int len = list1[i].size();
			ans=max(ans,len);
			for(int j=1;j<=len/2;++j){
				int l = list1[i][j-1],r = list1[i][len-j];
				for(int k=1;k<=200;++k)
					ans=max(ans,2*j+max(countt[k][r-1]-countt[k][l],0));
			}
		}
		printf("%d\n",ans);
		for(int i=1;i<=200;++i)
			for(int j=1;j<=n;++j)
				countt[i][j]=0;
	}
}
int main(void)
{
	solve();
	return 0;
 } 

F.Robots on a Grid

题意:
给你两个 n ∗ m n*m nm的矩阵.
第一个矩阵为每个格子的颜色,第二个矩阵为机器人在这个格子上的移动方向.
每个格子只能放一个机器人.
假设现在有 R L L RLL RLL,现在我们在 ( 1 , 1 ) (1,1) (1,1) ( 1 , 3 ) (1,3) (1,3)各放上一个机器人,那么下一秒,两个机器人都在 ( 2 , 2 ) (2,2) (2,2)格子上,这样便是不合法的.
求开始放置的机器人的合法的最多数量,在此前提下,同时输出机器人所在的黑色格子的最大数量.
题解:
题目保证任意格子开始移动,都不会走出 n ∗ m n * m nm矩阵外,说明是一个循环,且循环长度不超过 n ∗ m n * m nm.
假设当两个机器人在同一个格子相遇,那么两个机器人之后所有的移动都是在同一个格子上的.
现在我们在每一个格子都放上一个机器人,每个机器人都走 n ∗ m n * m nm步,最后如果会在途中相遇的机器人,一定会在走完 n ∗ m n * m nm后处于同一个格子.现在只需要求出所有机器人都走完 n ∗ m n * m nm后的位置,答案就出来了.
要求每一个位置走 n ∗ m n*m nm步之后的位置,用暴力肯定会超时,需要用倍增

#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e6+5;
int t,n,m,nxtX[MAX][22],nxtY[MAX][22],vis[MAX],ans1,ans2;
string s1,s2,s;
void solve(){
	scanf("%d",&t);
	while(t--){
		ans1=ans2=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n*m;++i) vis[i]=-1;
		s1=s2="0";
		for(int i=1;i<=n;++i){
			cin>>s;
			s1+=s;
		}
		for(int i=1;i<=n;++i){
			cin>>s;
			s2+=s;
		}
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				int index = (i-1)*m+j;
				if(s2[index]=='U')
					nxtX[index][0]=i-1,nxtY[index][0]=j;
				else if(s2[index]=='D')
					nxtX[index][0]=i+1,nxtY[index][0]=j;
				else if(s2[index]=='L')
					nxtX[index][0]=i,nxtY[index][0]=j-1;
				else
					nxtX[index][0]=i,nxtY[index][0]=j+1;
			}
		}
		for(int i=1;i<=20;++i){
			for(int j=1;j<=n;++j){
				for(int k=1;k<=m;++k){
					int index = (j-1)*m+k;
					int nxtIndex = (nxtX[index][i-1]-1)*m+nxtY[index][i-1];
					nxtX[index][i]=nxtX[nxtIndex][i-1];
					nxtY[index][i]=nxtY[nxtIndex][i-1];
				}
			}
		}
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				int index = (i-1)*m+j,X,Y;
				for(int k=0;k<=20;++k){
					if((1<<k)&(n*m)){
						index = (nxtX[index][k]-1)*m+nxtY[index][k];
						X=nxtX[index][k],Y=nxtY[index][k];
					}
				}
				if(vis[index]!=0) vis[index]=s1[(i-1)*m+j]-'0';
			}
		}
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				int index = (i-1)*m+j;
				if(vis[index]!=-1) ++ans1;
				if(vis[index]==0) ++ans2;
			}
		}
		printf("%d %d\n",ans1,ans2);
	}
}
int main(void)
{
	solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值