Codeforces Round #806 (Div. 4) 题解

昨晚闲的无聊,做套水题爽一爽~

A 题目链接:Problem - A - Codeforces

input:

10
YES
yES
yes
Yes
YeS
Noo
orZ
yEz
Yas
XES

output:

YES
YES
YES
YES
YES
NO
NO
NO
NO
NO

题意:

输入一串字符串,如果是 “ yes ” (大小写不限,比如 yEs ,YEs ),输出 YES ,否则输出 NO。

思路:

签到题,每个字符匹配一下对应大小写字符即可。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
 
int t; 
int main()
{
 	ios::sync_with_stdio(false);
 	cin>>t;
 	string s;
 	string ss="YES";
 	string sss="yes";
 	while(t--)
 	{
 		cin>>s;
 		bool flag=1;
 		for(int i=0;i<s.length();i++)
 		{
 			if(s[i]!=ss[i]&&s[i]!=sss[i])
			 {
			 	flag=0;
			 	break;
			}		
		}
		if(flag)
		{
			cout<<"YES"<<endl;
		}
		else
		{
			cout<<"NO"<<endl;
		}
	}
 	return 0;
}

B 题目链接:Problem - B - Codeforces

input:

6
3
ABA
1
A
3
ORZ
5
BAAAA
4
BKPT
10
CODEFORCES

output:

5
2
6
7
8
17

题意:

给一个长度为n的大写字母字符串,每种字母第一次出现时权值为2,否则权值为1,求字符串总权值

思路:

水题,开个bool数组记录一下是否第一次出现,暴力即可,注意每次memset vis数组

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
 
int t,n;
bool vis[30]; 
int main()
{
 	ios::sync_with_stdio(false);
 	cin>>t;
 	string s;
 	while(t--)
 	{
 		memset(vis,0,sizeof vis);
 		cin>>n;
 		cin>>s;
 		int ans=0;
 		for(int i=0;i<n;i++)
 		{
 			if(!vis[s[i]-65])
			{
				ans+=2;
				vis[s[i]-65]=1;	
			}
			else
			{
				ans++;	
			}	
		}
		cout<<ans<<endl;
	}
 	return 0;
}

C 题目链接:Problem - C - Codeforces

input:

3
3
9 3 1
3 DDD
4 UDUU
2 DU
2
0 9
9 DDDDDDDDD
9 UUUUUUUUU
5
0 5 9 8 3
10 UUUUUUUUUU
3 UUD
8 UUDUUDDD
10 UUDUUDUDDU
4 UUUU

output:

2 1 1 
9 0 
0 4 9 6 9 

题意:

有一个位数为n的密码锁,每位是0-9,现给出密码锁的最终组合,并给出对每位密码的操作过程(U代表该位数加1,D代表该位数减1,均0-9循环)求最初的密码锁组合是多少

思路:

前几题数据量太小了,直接暴力即可。读到U往下走,读到D往上走,就能反推最初组合,注意取模即可

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
int a[N];
int t,n,k; 
int main()
{
 	ios::sync_with_stdio(false);
 	cin>>t;
 	while(t--)
 	{
 		cin>>n;
 		for(int i=1;i<=n;i++)
 		{
 			cin>>a[i];
		}
		for(int i=1;i<=n;i++)
		{
			cin>>k;
			string s;
			cin>>s;
			for(int j=0;j<s.length();j++)
			{
				if(s[j]=='U')
				{
					a[i]--;
					if(a[i]==-1)
					{
						a[i]=9;
					}
				}
				else
				{
					a[i]++;
					if(a[i]==10)
					{
						a[i]=0;
					}
				}
			}
		}
		for(int i=1;i<=n;i++)
		{
			cout<<a[i]<<" ";
		}
		cout<<endl;
	}
 	return 0;
}

D 题目链接:Problem - D - Codeforces

input:

3
5
abab
ab
abc
abacb
c
3
x
xx
xxx
8
codeforc
es
codes
cod
forc
forces
e
code

output:

10100
011
10100101

题意:

给出n个小写字母字符串(长度不超过8),问对于字符串 ai (1 <= i <= n ),是否存在 aj ,ak      ( 1 <= j , k <= n ),使 ai = aj + ak (此处的“ + ”意为两个字符串拼接)。输出一串长度为n的01串,第 i 位 为1代表字符串 i 可以满足上述要求,0反之。

思路:

题干中指出的字符串长度不超过8非常关键,意味着我们可以直接暴力将一个字符串拆成两段,然后分别在字符串集合中匹配。开局直接将字符串存入set,然后对于每次拆分,用 set.count() ,查询是否存在即可,复杂度为 O( nlogn )级别。

注意每次set.clear()!

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int t,n; 
string s[N];
int main()
{
 	ios::sync_with_stdio(false);
 	cin>>t;
 	set<string> st;
 	while(t--)
 	{
 		cin>>n;
 		st.clear();
 		string ans="";
 		for(int i=1;i<=n;i++)
 		{
 			cin>>s[i];
			st.insert(s[i]);	
		}
		for(int i=1;i<=n;i++)
		{
			bool flag=0; 
			for(int j=0;j<s[i].length();j++)
			{
				string a=s[i].substr(0,j);
				string b=s[i].substr(j);
				if(st.count(a)&&st.count(b))
				{
					flag=1;
					break;
				}
			}
			cout<<flag;
		}
		cout<<endl;
	}
 	return 0;
}

E 题目链接:Problem - E - Codeforces

input:

5
3
010
110
010
1
0
5
11100
11011
01011
10011
11000
5
01000
10101
01010
00010
01001
5
11001
00000
11111
10110
01111

output:

1
0
9
7
6

题意:

给出形状为 n * n 的 正方形格子,每个格子的值为0或者1,现需令该正方形旋转0°,90°,180°,270°的形状均完全一致。每次可以对一个格子的值进行修改(1变0,0变1)。问最少需要修改多少次,可以满足上述要求。

思路:

n的数据量为100,完全可以在 O( n ^ 2 )复杂度内实现算法,所以直接找规律暴力。

观察可以发现,每个格子 a[i][j] 经过三次旋转,与其对应的位置为:

a[j][n-i+1] , a[n-i+1][n-j+1] , a[n-j+1][i]

所以,直接遍历左上半的1/4块部分,对其三次旋转后的位置进行处理,看全改为0,全改为1哪个代价最小。

对于n为奇数的情况,我们需要对 n / 2 + 1的部分(即最中央的十字架)进行特判处理,处理方式同上。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
int a[N][N];
int t,n;
int main()
{
 	ios::sync_with_stdio(false);
 	cin>>t;
 	while(t--)
 	{
 		cin>>n;
 		char c;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				cin>>c;
				a[i][j]=c-48;	
			}	
		}
		int ans=0;
		for(int i=1;i<=n/2;i++)
		{
			for(int j=1;j<=n/2;j++)
			{
				int k=a[i][j]+a[j][n-i+1]+a[n-i+1][n-j+1]+a[n-j+1][i];
				ans+=min(k,4-k);
			}
		}
		if(n%2)
		{
			for(int i=1;i<=n/2;i++)
			{
				int k=a[n/2+1][i]+a[n/2+1][n-i+1]+a[i][n/2+1]+a[n-i+1][n/2+1];
				ans+=min(k,4-k);
			}
		}
		cout<<ans<<endl;	
	}
	
 	return 0;
}

F 题目链接:Problem - F - Codeforces

input:

5
8
1 1 2 3 8 2 1 4
2
1 2
10
0 2 1 6 3 4 1 2 8 3
2
1 1000000000
3
0 1000000000 2

output:

3
0
10
0
1

题意:

给定长度为n的数组a,寻找所有 ai , aj组合, 令 ai < i < aj < j ,输出这个数

思路:

先处理一遍输入,保留 所有 ai < i , 开两个数组分别记录一下 满足要去的 id 和 val ,对 val 数组进行sort,然后 对 id 数组的每个元素在 val 数组中 upper_bound 一下,记录位置为k,则当前第 i 个元素,对其满足 ai < i < aj < j 的 aj 有 cnt - k + 1个,每次记录答案

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int N=2e5+10;
int t,n;
 
ll a[N],val[N],id[N];
 
int main()
{
 	ios::sync_with_stdio(false);
 	cin>>t;
 	while(t--)
 	{
 		cin>>n;
 		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			if(a[i]<i)
			{
				id[++cnt]=i;
				val[cnt]=a[i];	
			}	
		}
		sort(val+1,val+cnt+1);
		ll ans=0;
		for(int i=1;i<=cnt;i++)
		{
			ll k=upper_bound(val+1,val+cnt+1,id[i])-val;
			ans+=cnt-k+1;		
		}
		cout<<ans<<endl;	
	}
 	return 0;
}

G 题目链接:Problem - G - Codeforces

 

input:

5
4 5
10 10 3 1
1 2
1
3 12
10 10 29
12 51
5 74 89 45 18 69 67 67 11 96 23 59
2 57
85 60

output:

11
0
13
60
58

题意:

现有n个箱子,第 i 个箱子中含有 ai 个硬币,现需按1-n的顺序开箱。给定一个k,可以每次花费k个硬币的代价开一次箱子,称为 Goodkey ,也可令 ai ,ai+1, …… , an均减半,来打开 第 i 个箱子,称为 Badkey. 开箱过程中可以存在负债情况。问开完所有箱子之后,最多能获得多少硬币

思路:

思维题。分析题意,我们可以得到以下结论:一旦使用了badkey,后面所有箱子都要使用badkey来开启才能保证最优。

证明:对于任意 i ,i + 1 ( 1 <= i <= n-1 )

先goodkey,后badkey,获得的金币数为 a[i] - k + a[i+1] / 2

先badkey,后goodkey,获得的金币数为 a[i] / 2 + a[i+1] / 2 - k

显然情况1收益大于情况2,证毕

又因为 ai不超过1e9,所以最多badkey30次后,后面的所有数就变0了,就不用管了

所以消耗 O(30 * n )的复杂度可以完成操作

遍历 n 次,每次从i开始,ans加上 i-1 的前缀和,减去 k * ( i - 1 ) , 然后向后遍历30次(指针不超过n)每次做badkey,并加入ans,每次对 i 的遍历后,取最大的ans

切记与答案有关的运算,变量均开 long long!!!因为这个点 wa 了两发,气!

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int N=2e5+10;
ll t,n=0,k;
ll a[N];
ll s[N]; 
int main()
{
 	ios::sync_with_stdio(false);
 	cin.tie(0);
 	cout.tie(0);
 	cin>>t;
 	while(t--)
 	{
 		for(int i=1;i<=n;i++)
 		{
 			s[i]=0;
		}
 		cin>>n>>k;
		for(int i=1;i<=n;i++)
	    {
	    	cin>>a[i];
	    	s[i]=s[i-1]+a[i];
		}
 
		ll maxans=0;
		for(ll i=1;i<=n+1;i++)
		{
			ll ans=s[i-1]-k*(i-1);
			for(ll j=i;j<=i+30&&j<=n;j++)
			{
				ans+=ll(a[j]/pow(2,j-i+1));
			}
			maxans=max(ans,maxans);
		}
		cout<<maxans<<endl;				
	 }
 	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值