Codeforces Round #674 (Div. 3) 题解

A. Floor Number

题意:

有一栋楼,第一层有两个房间(编号 1 , 2 1,2 1,2),第二层有 x x x个房间(编号 3 , 4 , . . . , 2 + x 3,4,...,2+x 3,4,...,2+x),以后每一层也都是 x x x个房间,现在给你房间编号,输出它得楼层。

解题思路:

理解题意后直接做就好了。

代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int main(){
int t;
cin>>t;
while(t--)
{
	int n,m;
	cin>>n>>m;
	int ans = 1+(n-2)/m;
	if((n-2)%m)ans++;
	if(n <= 2)ans=1;
	cout<<ans<<endl;
}
return 0;
}

B. Symmetric Matrix

题意:

给你 n n n 2 ∗ 2 2*2 22得瓷砖(每格都有颜色),能否将 m ∗ m m*m mm的矩形都填上瓷砖,满足 s [ i ] [ j ] = s [ j ] [ i ] ( 1 ≤ i , j ≤ m , s [ i ] [ j ] 表 示 矩 形 i 行 j 列 的 颜 色 ) s[i][j]=s[j][i](1\leq i,j \leq m,s[i][j]表示矩形i行j列的颜色) s[i][j]=s[j][i]1i,jms[i][j]ij

解题思路:

1、 m m m是奇数肯定不行。
2、当 m m m偶数,观察发现只要 2 ∗ 2 2*2 22的瓷砖的左下角和右上角一样就可行。

代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int main(){
	int t;
	cin>>t;
	while(t--)
	{
		int n,m;
		cin>>n>>m;
		int f = 0;
		for(int i=0;i<n;i++)
		{
			int a,b,c,d;
			cin>>a>>b>>c>>d;
			if(b==c)
				f=1;
		}
		if(m%2 || f==0)
			cout<<"NO"<<endl;
		else
			cout<<"YES"<<endl;
	} 
	return 0;
}

C. Increase and Copy

题意:

有个数组 a a a,开始只有一个元素 a [ 0 ] = 1 a[0]=1 a[0]=1,每次操作你可以选择以下之一:
1、选择数组中的一个元素 + 1 +1 +1
2、复制数组中的一个元素到数组末尾。
现在要让数组中的元素和为 n n n,至少需要几次操作?

解题思路:

如果我们考虑 x x x次操作能得到的最大数组和,如果既有操作1,又有操作2,那么一定先执行所有操作1,之后再执行操作2。

当我们要得到的数组和为 n n n时,假设执行了 x 1 x1 x1次操作1,那么还需要执行操作2的次数是 ⌈ n x 1 ⌉ \lceil \frac{n}{x1} \rceil x1n ,当我打算枚举 x 1 x1 x1时想起高中的公式: a + b ≥ 2 ∗ a ∗ b a+b \geq 2*\sqrt{a*b} a+b2ab a = b a=b a=b时等号成立,,那么我只要让 x 1 x1 x1接近 n \sqrt{n} n 就好了。

代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int main(){
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		int c = sqrt(n);
		if(c*c != n)
			c++;
		int d = n/c;
		if(n%c)d++;
		int ans = (c-1)+(d-1);
		cout<<ans<<endl;
	} 
	return 0;
}
 

D. Non-zero Segments

题意:

给你一个没有 0 0 0的数组,你要在其中插入尽量少的元素,让这个数组的子数字(连续的)的和都不为 0 0 0(你插入的这个数可以是很大的)

解题思路:

s u m [ i ] sum[i] sum[i]表示前 i i i个元素的前缀和,那么如果存在以 i i i结尾的子数组的和为 0 0 0,一定存在 s u m [ j ] = s u m [ i ] ( j < i ) sum[j]=sum[i](j < i) sum[j]=sum[i](j<i),我们可以用map记录已经出现过的前缀和,而且如果存在以 i i i结尾的子数组的和为 0 0 0的情况,我需要在 i i i前面插入一个数,我们插入一个“很大”的数,因为这样前面出现过的前缀和就没用了,我们需要清空下map。

代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
map<long long,int> mp;
int main(){
	long long n,ans=0,sum=0;
	mp[0]=1;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		long long a;
		cin>>a;
		sum += a;
		if(mp[sum])
		{
			ans++;
			mp.clear();
			mp[0]=1;
			sum = a;
		}
		mp[sum] = 1;
	} 
	cout<<ans<<endl;
	return 0;
}

E. Rock, Paper, Scissors

题意:

Alice和Bob猜拳,知道他们出石头剪刀布的次数,问Alice至少能赢几把和至多能赢几把。

解题思路:

1、最多能赢:就是Alice的石头能对上多少Bob的剪刀就对上,Alice的剪刀能对上多少Bob的布就对上,Alice的布能对上多少Bob的石头就对上,设Alice和Bob的石头剪刀布分别是 a 1 , a 2 , a 3 , b 1 , b 2 , b 3 a1,a2,a3,b1,b2,b3 a1,a2,a3,b1,b2,b3,那么答案就是 m i n ( a 1 , b 2 ) + m i n ( a 2 , b 3 ) + m i n ( a 3 , b 1 ) min(a1,b2)+min(a2,b3)+min(a3,b1) min(a1,b2)+min(a2,b3)+min(a3,b1)
1、最少能赢:就是Alice的石头至少会对上多少Bob的剪刀,其实就是尽量让Alice的石头去对Bob石头和布,如果还有剩下那么就只能对剪刀,那么就是 m a x ( 0 , ( a 1 − ( b 1 + b 3 ) ) ) max(0,(a1-(b1+b3))) max(0,(a1(b1+b3)))(剪刀、布同理)。

代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int main(){
	int n,a1,a2,a3,b1,b2,b3;
	cin>>n;
	cin>>a1>>a2>>a3>>b1>>b2>>b3;
	int ans2 = min(a1,b2)+min(a2,b3)+min(a3,b1);
	int ans1 = 0;
	ans1 += max(0,(a1-(b1+b3)));
	ans1 += max(0,(a2-(b1+b2)));
	ans1 += max(0,(a3-(b2+b3)));
	cout<<ans1<<" "<<ans2<<endl;
	return 0;
}

F. Number of Subsequences

题意:

有一个字符串只包含’a’、‘b’、‘c’、’?’,’?‘可以变成’a’、‘b’、‘c’中任意字符,问’?'变成的所有情况下(共有 3 x 3^x 3x x x x表示‘?’出现的次数),有多少个子串"abc"。具体看样例。

解题思路:

如果没有‘?’,那就简单了,和这题一样可以看下。如果当前是’?’:
1、那么已有的子串“a”的贡献(设 a [ 1 ] a[1] a[1])个数要乘3,因为我不管填什么前面的 a [ 1 ] a[1] a[1]都会有一遍贡献,之后还需要 a [ 1 ] + + a[1]++ a[1]++(这个’?‘我填’a‘)
2、已经有的子串“ab”的贡献(设 a [ 2 ] a[2] a[2])个数要乘3,然后 a [ 2 ] + = a [ 1 ] a[2]+=a[1] a[2]+=a[1]
3、已经有的子串“abc”的贡献也就是答案(设 a n s ans ans)也要乘3,然后ans+=a[2]。
但是这样发现错了,原来是 a [ 1 ] a[1] a[1]少算了,因为如果当前是“a”,它的贡献并不只是1,在这之前的所有’?‘我不管填什么这个’a’都会加贡献,所以还需要一个变量表示前面出现了几个’?’,那么当前’a’的贡献就是3*(’?‘的个数),那么就有了:
4、 a [ 0 ] ∗ = 3 a[0]*=3 a[0]=3
并且改正前面1、的 a [ 1 ] + + a[1]++ a[1]++ a [ 1 ] + = a [ 0 ] a[1]+=a[0] a[1]+=a[0]
s [ i ] s[i] s[i]不等于’?'时思路差不多,只是不乘3变成相应的乘1,看代码。

代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
const int mod = 1e9+7;
char s[maxn];
long long n,a[5];
int main(){
	long long ans=0;
	cin>>n>>s;
	memset(a,0,sizeof(a));
	a[0]=1;
	for(int i=0;i<n;i++)
	{
		if(s[i]=='a')
			a[1]+=a[0];
		else if(s[i]=='b')
			a[2]+=a[1];
		else if(s[i]=='c')
			ans+=a[2];
		else
		{
			ans*=3; 
			ans+=a[2];
			a[2]*=3;
			a[2]+=a[1];
			a[1]*=3;
			a[1]+=a[0];	
			a[0]*=3;
		}
		a[0]%=mod;a[1]%=mod;a[2]%=mod;
		ans%=mod;
	}
	cout<<ans<<endl;
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值