日期:2023.10.3
学号:S06465
一:
总分数:
T1【称心如意(satisfied)】:100
T2【AC万岁(acok)】:100
T3【解救达达(rescue)】:40
T4【整理文本(text)】:0
二、比赛过程
第一道题送分题,读懂题目就能拿满分
第二道题也很简单,就是要注意一下a在c后面不算ac
第三道题我用的是暴力枚举,得了40
第四道题我用的暴力枚举,我的思路对了,但是没有考虑空格,得0分
三、比赛分析
T1【称心如意(satisfied)】:
1.题目大意
小可有一个数字,让你根据要求找到一个与其匹配的序列
2、比赛中的思考
我是读懂题目以后,直接根据要求模拟的
3、解题思路
根据题目要求直接模拟就可以了
4.AC代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
for(int i=0;i<=n;i++){
int f=0;
for(int j=1;j<=9;j++){
if(n%j==0&&i%(n/j)==0&&f==0){
f=1;
cout<<j;
}
}
if(f==0){
cout<<"-";
}
}
return 0;
}
T2【AC万岁(acok)】:
1.题目大意
给你一个字符串,让你求ac作为字符串子序列出现的次数
2.比赛中的思考
我一开始想的是统计出a和c出现的次数,然后输出把它们相乘的结果,后来想到a在c的后面不算ac,然后又想的如果遇到a就让cnt++,如果碰到c就让sum加上cnt
3.解题思路
for循环遍历字符串s,如果遇到a,就让计数器++,如果遇到c就让sum+=计数器,最后输出sum
4.AC代码
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin>>s;
int a=0,cnt=0;
for(int i=0;i<s.size();i++){
if(s[i]=='a'){
a++;
}
if(s[i]=='c'){
cnt+=a;
}
}
cout<<cnt;
return 0;
}
T3【解救达达(rescue)】:
1.题目大意
给你一个区间[a,b]让你求这个区间内,把这几个数转成二进制,这个二进制里有一个只有一个0的数
2.比赛中的思考
我是这样想的,先for循环遍历a到b,然后再把i转成二进制数,如果这个二进制位上有一个0,就让计数器++,如果计数器等于1,就让sum++,最后输出sum
3.解题思路
先记录一下a和b转成二进制是几位数,然后在用循环枚举,用((long long)1<<cnt1)-1,求出这个cnt1位的二进制最大的数,然后for循环枚举,每一次都用x^((long long)1<<j),把它的第j位变成0,如果这个二进制大于等于a并且小于等于b,让cnt++,最后输出cnt
4.AC代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
long long a, b;
cin >> a >> b;
long long cnt = 0;
for (int i = 1; i <= 63; i ++) {
for (int j = 0; j < i - 1; j ++) {
long long sum = (1ll << i) - 1 - (1ll << j);
if (sum >= a && sum <= b)
cnt ++;
}
}
cout << cnt;
return 0;
}
T4【整理文本(text)】:
1.题目大意
给你n个单词,让你整理这些单词,并且要把行数控制在m行以内,两个单词之间至少要有一个空格,单词不能调换顺序,并且单词不能舍弃一部分
2.比赛中的思考
我想的是用for循环枚举它的宽度,如果sum加a[i]小于等于i,就让sum加上a[i],如果大于i就让sum等于0,cnt++,如果cnt小于等于m,就用它和minn比较,如果minn比它大,就让minn等于cnt
3.解题思路
可以用二分答案来解决,用一个函数来判断这个宽度可不可以满足要求,如果可以,就让r=mid,继续寻找看看有没有更小的答案,如果不可以就让l=mid+1,直接越过这个去继续寻找
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\n",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
}