原题地址: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;
}