Codeforces Round #833 (Div. 2)部分题解A~C

原题地址:Codeforces Round #833 (Div. 2)

题目:A. The Ultimate Square

题意:

        有n个长方形,它们的长宽依次为1*(n/2),例如n=5,长永远是1,宽是 1/2 = 1,2/2 = 1,3/2=2,4/2=2,5/2=3;就是向上取整。思路就是它最终组长的最大的正方形的变成是n/2向上取整,这是必定的,自己推一下几个例子即可。

 代码:

#include<bits/stdc++.h> 
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<string.h> 
typedef long long ll;
using namespace std;
const int N = 2e5+10;
const int mod = 1e9+7;
ll a[N],b[N],c[N];
//string s1[N],s2[N],s3[N];
int main(void)
{
	int t;
	cin >> t;
	while(t--)
	{
		ll n;
		cin >> n;
		ll res = ceil(n/2.0);
		cout << res << endl;
	}
	return 0;
 } 

题目:B. Diverse Substrings

题意:

        给定一个长度为n的字符串s,求它的子串满足diverse串的个数,子串个数是 n*n+1 / 2,

思路是遍历每个子串看是否满足即可,当子串的长度大于100时,因为dis不同的个数最多等于10,而maxv最大的相同个数最小是大于10的,所以后面的都不满足。

 代码:

#include<bits/stdc++.h> 
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<string.h> 
typedef long long ll;
using namespace std;
const int N = 2e5+10;
const int mod = 1e9+7;
ll a[N],b[N],c[N];
int d[10];
//string s1[N],s2[N],s3[N];
int main(void)
{
	int t;
	cin >> t;
	while(t--)
	{
		int n;
		cin >> n;
		string s;
		cin >> s;
		ll sum=n;
		for(int i=0;i<s.length();i++)
		{
			memset(d,0,sizeof d);
			int maxv=0;//最多的那个相同点 
			int dis=0;//一个字串中不同的点的个数 
			int x = s[i]-'0';
			d[x]++;
			dis++;
			for(int j=i+1;j<s.length();j++)
			{
				if(j-i>=100)//子串长度大于100后面的肯定不满足
					break;
				int num = s[j]-'0';
				if(!d[num])
				{
					dis++;
				}
				d[num]++;
				maxv = max(maxv,d[num]);
				//cout << maxv << " " << dis << endl;
				if(dis>=maxv)
					sum++;
			}
		}
		cout << sum << endl;
	}
	return 0;
 } 

题目:C. Zero-Sum Prefixes

题意:

        给定一个长度为n的数列a,我们只能改变ai = 0的值为任意一个值,求最后满足a1+a2+...+ai=0的子序列的个数。做法是:我们先记录每个0的下标,这是可以改变的位置,记录每一个a的前缀和,当第一个0出现之前的那些数,我们无法改变,所以只要s【i】 == 0时,ans++即可这是默认的,然后从第一个0出现的下标开始遍历,

如a = 2 0 1 -1 0,第一个0出现的下标是2,第二个0出现的下标是5,所以遍历2~4之间的前缀和

s[2] = 2,s[3] = 3,s[4] = 2,可以发现2出现的个数是最多的是2个,所以我们就会将第一个0改为-2,让s[2] = 0,那么s[4]也自然而然变成0了,所以ans = 2,然后s[5]=0,ans = 3了

如a = 3 0 2 -10 10 -30 30 0,s[2] = 3,s[3] = 5,s[4] = -5,s[5] = 5,s[6] = -25,s[7] = 5

5出现了3次,所以我们将前缀和为5的变为0,所以将第一个0改为-5即可,这样ans = 3;最后再加上s[8] = 0,ans = 4即可,以此类推

当a = 1 0 0 1 -1 0 1 0 -1时,s[2] = 1,s[3] = 1,这俩个0之间改第一个0为-1即可,ans=1,改变后s[3]=0,s[4]=1,s[5]=0,0的个数是最多的,所以我们不用去改,ans = 1+2 = 3,第三个0下标s[6] = 0,s[7] = 1,因为0 和 1 的数量是相同的,改和不改都是一样的,这里我们将a[6]变为-1,那么s[6] = -1,s[7] = 0,ans = 3+1 = 4;第4个0也就是a[8] = 0,s[8] = 0,s[9] = -1,我们改不改还是一样的,ans = 4+1 = 5

代码:

        

#include<bits/stdc++.h> 
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<string.h> 
typedef long long ll;
using namespace std;
const int N = 2e5+10;
const int mod = 1e9+7;
ll a[N],b[N],c[N];
//string s1[N],s2[N],s3[N];
int main(void)
{
	int t;
	cin >> t;
	while(t--)
	{
		int n;
		cin >> n;
		int len=0;//记录0的位置下标 
		for(int i=1;i<=n;i++)
		{
			cin >> a[i];
			b[i] = b[i-1]+a[i];//前缀和 
			if(a[i]==0)
				c[len++] = i;
		}
		c[len] = n+1; //保证c[len] = 0,即最后一个的数字的下一个数是0
		ll ans=0;//记录结果 
		//在第一个零出现以前,前面是无法处理的,ans是固定的
		for(int i=1;i<c[0];i++)
		{
			if(b[i]==0)
				ans++;
		} 
		map<ll,int> m;
		for(int i=0;i<len;i++)
		{
			m.clear();
			int ma=0;
			for(int j=c[i];j<c[i+1];j++)
			{
				m[b[j]]++;
				ma = max(ma,m[b[j]]);
			}
			ans+=ma;
		}
		cout << ans << endl;
	}
	return 0;
 } 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值