日期:2023-10-3
学号:S11972
一、总分数:
T1【称心如意(satisfied)】:100
T2【AC万岁(acok)】:10
T3【解救达达(rescue)】:20
T4【整理文本(text)】:0
二、比赛过程
第一题就是一个模拟题,根据题目描述给的条件去写就行,测试点也不大,拿了全分,水题。
第二题是一个枚举题,但是不是纯枚举,要先找到a往后判断是不是c,然而我把ca也算进去了,得了10分。(话说这十分是怎么拿的)
第三题考了位运算,但是我没想到用,直接用的纯暴力枚举,只得了20分。
第四题用的是二分答案,奈何没学过,也没找到可以枚举的点,没得分。
三、比赛分析
T1【称心如意(satisfied)】
1、题目大意
按照描述里的条件一个字符一个字符判断输出,得到一个序列。
2、比赛中的思考
想到这题是个模拟题,就按照条件写,就直接对了。
3、解题思路
(1)循环n次,取j的值
(2)定义flag判断是否输出 ‘ - ’
4、AC代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin>>n;
for(int i=0; i<=n; i++) {
int f=1;
for(int j=1; j<=9; j++) {
if(i%(n/j)==0&&n%j==0) {
cout<<j;
f=0;
break;
}
}
if(f==1) {
cout<<'-';
}
}
return 0;
}
T2【AC万岁(acok)】
1、题目大意
给定一个字符串,计算ac
作为字符串子序列出现的次数。
字符串子序列指的是从最初字符串通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。例如,acf、bde、bcd都是abcdef的子序列,而cae并不是。
2、比赛中的思考
这题我想到用两个计数器计算a和c的个数,但是没想到这玩意把ca也算进去了,就对了一组样例。(就挺后悔的)
3、题目思路
可以直接枚举字符串,每遇到一个字符a ,计数器加1,每遇到一个字符c,累加器加上计数器,统计答案。
4、AC代码
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
cin>>s;
int len=s.size(),cnt=0,a=0;
for(int i=0; i<len; i++) {
if(s[i]=='a') a++;
if(s[i]=='c') cnt+=a;
}
cout<<cnt;
return 0;
}
T3【解救达达(rescue)】
1、题目大意
求区间[a,b],有多少个数字的二进制有0
如果数字的二进制中有两个及以上的0
(前导 0
不算,即从第一个非0
数表示二进制)则不统计。
2、比赛中的过程
这题我用的纯暴力枚举(因时间超限直接爆炸),跟本就没想到用位运算。
3、解题思路
先算出a在二进制中的位数(l),再算出b在二进制中的位数(r),枚举l~r的所有情况。
定义x,y
x用来存放用来判断的数 例:l=6 x=11111
y用来存放答案。
4、AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
ll a,b,A,B,l=0,r=0,x=0,ans=0;
cin>>a>>b;
A=a;B=b;
while(A){
l++;
A/=2;
}
while(B){
r++;
B/=2;
}
while(l<=r){
ll x=((ll)1<<l)-1;
for(ll j=0;j<l-1;j++){
ll y=x^((ll)1<<j);
if(y>=a&&y<=b){
ans++;
}
}
l++;
}
cout<<ans;
return 0;
}
T4【整理文本(text)】
1、题目大意
小可数出了文本中总共有 N个单词,并且小可记录出来了每个单词的长度 L。
整理出来的文本必须要满足行首为当前行的第一个单词,相邻的两个单词需至少由一个空格间隔。
当所有文本按照要求整理结束之后,得到每一行的行宽(当前行中单词的 ∑Li ;加 空格数量),请使得其中最大的行宽最小,请输出对应的行宽值。
单词不能调换顺序,并且单词不能舍弃一部分。
2、比赛中的过程
看懂了题,但没学过二分答案(悲
3、题目思路
宽度的取值一定是具有单调性的,可以进行二分查找,二分的范围为,每个单词的最大长度到一个很大的数字(可以装下全部单词),然后贪心验证每个枚举出来的宽度是否满足 行装下所有单词。
4、AC代码
#include<bits/stdc++.h>
#define N 220000
using namespace std;
long long a[N]= {},m=0,mx=0,n=0;
bool calc(long long num);
int main() {
scanf("%lld%lld",&n,&m);
for(long long i=1; i<=n; i++) {
scanf("%lld",&a[i]);
mx=max(mx,a[i]);
}
//输入,并找到单词长度最大值
long long l=mx-1,r=1e15+1;
//确定双端便边界,开始二分
while(l+1<r) {
long long mid=(l+r)/2;
if(calc(mid)==false) {
l=mid;
} else {
r=mid;
}
}
printf("%lld",r);
//输出答案r
return 0;
}
bool calc(long long num) {
long long now=1,sum=-1;
//now为当前用到第几行,sum表示用到第now行的第几列 //初始值是为了把第一个单词前面的空格磨平
for(long long i=1; i<=n; i++) {
if(sum+1+a[i]<=num) {
sum=sum+1+a[i];
//当前行能在放就放
} else {
sum=a[i];
now++;
//放不了就另起一行
}
}
if(sum==-1) {
now--;
}
//把初始值的误差过滤掉
if(now<=m) {
return true;
}
//符合条件返回true
return false;
//否则返回false
}