L1-002 打印沙漏 (20 分)
不算沙漏下面,上面部分随着行数增加,字符的总数依次是1,4,9,16…满足row2×2-1<=n,逆推得上半部分行数(算上1)row=sqrt((n+1)/2),行最大字符数=2×row-1。剩下的for循环实现。
L1-003 个位数统计 (15 分)
用map和数组统计,可以直接char数组,和dodo那题字符类型的通用了(例如按字典序输出一行英文句子每个单词的出现个数)
ps:pta用不了gets,可以改用cin.getline
#include<bits/stdc++.h>
using namespace std;
int main()
{
char a[1005];
map<char,int>mp;
cin.getline(a,1005);
int len=strlen(a);
for(int i=0;i<len;++i) mp[a[i]]++;
map<char,int>::iterator it;
for(it=mp.begin();it!=mp.end();it++)
cout<<it->first<<":"<<it->second<<endl;
return 0;
}
L1-006 连续因子 (20 分)
看数据范围,暴力肯定不行,就一边2~sqrt(n)遍历试根一边求区间并更新起始点和最大区间长度。注意:1不算在序列内,所以要从2开始
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll n,len=0,st,maxx=0;
int main()
{
cin>>n;
for(ll i=2;i<=sqrt(n);i++)
{
ll x=n,xi=i,len=0;
while(x%xi==0)//一旦试根成功就求区间
{
x=x/xi;
xi++;
len++;
}
if(len>maxx) //必须是> 不能是>=
{ //因为要保证是最长的同时是最小序列,即st要最小
maxx=len;
st=i;
}
}
if(maxx==0) printf("1\n%lld",n); //考虑质数情况 序列即本身
else
{
cout<<maxx<<endl;
for(int i=1;i<=maxx;i++)
{
if(i==1) printf("%lld",st);
else printf("*%lld",st);
st++;
}
}
return 0;
}
L1-009 N个数求和 (20 分)
因为没开ll白花了半个小时…老经典了。通分 —> 特判t==1 —> 特判和为0 —> 约分 —> 判断符号 —> 分离整数 —> 根据分离后结果处理输出形式。注意:如果和为负数 ,那么之后分离整数时整数和分子都要自带负号 。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
struct Rational
{
ll n,d;
}num[105];
ll mod,fz,fm,zs;
int main()
{
ll t,fh=1;
cin>>t;
for(ll i=1;i<=t;i++) scanf("%lld/%lld",&num[i].n,&num[i].d);
if(t==1)
{
if(num[1].n==0)
{
printf("0");
return 0;
}
mod=gcd(abs(num[1].n),abs(num[1].d));
fz=num[1].n/mod;
fm=num[1].d/mod;
fh=fz/abs(fz);
if(abs(fz)>=fm)
{
fh?zs=fz/fm:zs=-fz/fm;
fz=fz%fm;
}
if(fz==0) printf("%lld",zs);
else abs(zs)?printf("%lld %lld/%lld",zs,fz,fm):printf("%lld/%lld",fz,fm);
return 0;
}
for(ll i=1;i<=t-1;i++)
{
fm=num[i].d*num[i+1].d;
fz=num[i].n*num[i+1].d+num[i+1].n*num[i].d;
num[i+1].n=fz;
num[i+1].d=fm;
}
if(fz==0)
{
printf("0");
return 0;
}
mod=gcd(abs(fz),abs(fm));
fm/=mod;
fz/=mod;
fh=(fm/abs(fm))*(fz/abs(fz));
if(abs(fz)>=fm)
{
fh?zs=fz/fm:zs=-fz/fm;
fz=fh*abs(fz)%fm;
}
if(abs(fz)==0) printf("%lld",zs);
else abs(zs)?printf("%lld %lld/%lld",zs,fz,fm):printf("%lld/%lld",fz,fm);
return 0;
}
L1-011 A-B (20 分)
因为字符串的每个字符必有ASCII码,所以出现的字符ASCII码范围必在255以内,用vis[]数组初始化为0后遍历b字符串并标记出现过的字符的对应vis值为1,再遍历a字符串,如果对应vis数组的值为0则输出,否则continue。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e4+5;
int vis[255];
int main()
{
string a,b;
getline(cin,a);
getline(cin,b);
memset(vis,0,sizeof(vis));
int lena=a.length(),lenb=b.length();
for(int i=0;i<lenb;i++) vis[b[i]]=1;
for(int i=0;i<lena;i++)
{
if(vis[a[i]]) continue;
else printf("%c",a[i]);
}
return 0;
}
L1-017 到底有多二 (15 分)
遍历字符串。注意:倍数是初始值为1,负数则再乘1.5,要是还是偶数则再乘2.0,例如负偶数的倍数=1×1.5×2.0,负奇数的倍数=1×1.5,正偶数的倍数=1×2.0
L1-020 帅到没朋友 (20 分)
找k==1时 出现的id或没出现过 的id。用vis数组标记id是否出现过(注意:如果k==1,即朋友圈只有一个人,那么也是属于“没朋友”,无需标记vis数组 ),记得输出后标记出现过,因为可能会有重复查询。几个小细节:①行末空格问题。 如果一边输入一边判断输出,那么如果最终结果只有一个时行末空格就会多出来,所以可以先for循环数 一下“没朋友的人”是否>1,分类讨论输出。②输出id格式问题。 因为必是五位数字,那么如果高位没有数字则要补0,所以输出时格式为**%05d** 。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+5;
int vis[maxn],a[maxn];
int main()
{
int n;
scanf("%d",&n);
memset(vis,0,sizeof(vis));
int flag=0;
while(n--)
{
int k;
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
int x;
scanf("%d",&x);
if(k!=1) vis[x]=1;
}
}
int m,t=0;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
if(vis[x]==0)
{
a[++t]=x;
flag=1;
vis[x]=1;
}
}
if(t==1) printf("%05d",a[1]);
else
{
for(int i=1;i<=t;i++)
{
printf("%05d",a[i]);
if(i!=t) cout<<" ";
}
}
if(flag==0) printf("No one is handsome");
return 0;
}
L1-023 输出GPLT (20 分)
①全部转换成大写(transform函数实现)②各个字母计数 ③按序输出直到没有字母剩下
知识点补充: transform函数可以转换string字符串中字母的大小写(数字或其他字符不影响)。
string s;
transform(st,ed,st,::tolower) //整体转换小写示例
st和ed和pos都是迭代器。
把s字符串[st,ed]区间的子串转换成
小写(tolower)或大写(toupper)
eg.
s="abcdefg";
transform(s.begin(),s.end(),s.begin(),::toupper);
输出内容为:ABCDEFG
s="abcdefg";
transform(s.begin()+2,s.end()-2,s.begin()+2,::toupper);
输出内容为:abCDEfg
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int main()
{
string s;
cin>>s;
transform(s.begin(),s.end(),s.begin(),::toupper);
int len=s.length(),gg=0,pp=0,ll=0,tt=0;
for(int i=0;i<len;i++)
{
if(s[i]=='G') gg++;
if(s[i]=='P') pp++;
if(s[i]=='L') ll++;
if(s[i]=='T') tt++;
}
int maxx=max(max(gg,pp),max(ll,tt));
for(int i=1;i<=maxx;i++)
{
if(gg)
{
cout<<"G";
gg--;
}
if(pp)
{
cout<<"P";
pp--;
}
if(ll)
{
cout<<"L";
ll--;
}
if(tt)
{
cout<<"T";
tt--;
}
}
return 0;
}
L1-025 正整数A+B (15 分)
有很多细节要注意,①读取 ②如果是数字还得要求在区间内 ③有一种很坑的情况,例如:【输入:1 1 1】【输出:1 + ? = ?】而不是【1 + 1 = 2】或【? + ? = ?】!!!
我自己的代码很繁琐
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e3+5;
char a[maxn],b[maxn],ch;
int t=1,aa=0,bb=0,flaga=1,flagb=1,x=0,y=0;;
bool judge(char ch)
{
if(ch>='0'&&ch<='9') return true;
else return false;
}
int main()
{
while(scanf("%c",&ch))
{
if(t==1)
{
if((aa==0&&(!judge(ch)||ch=='0'))||(!judge(ch)&&ch!=' ')) flaga=0;
else if(flaga&&ch!=' ') a[aa++]=ch;
}
if(t==2)
{
if((bb==0&&!judge(ch))||(!judge(ch)&&ch!=' '&&ch!='\n')) flagb=0;
else if(flagb&&ch!='\n') b[bb++]=ch;
}
if(ch==' ') t++;
if(ch=='\n') break;
}
if(t>2) flagb=0;
if(flaga==0) printf("? + ");
else
{
for(int i=0;i<aa;i++) x=x*10+a[i]-'0';
if(x>=1&&x<=1000) printf("%s + ",a);
else
{
printf("? + ");
flaga=0;
}
}
if(flagb==0) printf("? = ");
else
{
for(int i=0;i<bb;i++) y=y*10+b[i]-'0';
if(y>=1&&y<=1000) printf("%s = ",b);
else
{
printf("? = ");
flagb=0;
}
}
if(flaga*flagb==0) printf("?");
else printf("%d",x+y);
return 0;
}
看到一个比我少一半代码量的码,可以参考一下。要巧用字符串,也要写得干净利落,学习学习。
#include<bits/stdc++.h>
using namespace std;
string a,b;
int checkIt(string str){
int sum=0;
for(int i=0;i<str.length();i++){
if(isdigit(str[i])){
sum=sum*10+str[i]-'0';
}else{
return -1;
}
}
if(sum>=1&&sum<=1000) return sum;
else return -1;
}
int main(){
cin>>a;
getchar();
getline(cin,b);
int sumA=checkIt(a);
int sumB=checkIt(b);
if(sumA==-1) printf("? + ");
else printf("%d + ",sumA);
if(sumB==-1) printf("? = ");
else printf("%d = ",sumB);
if(sumA==-1 || sumB==-1) printf("?\n");
else printf("%d\n",sumA+sumB);
return 0;
}
L1-028 判断素数 (10 分)
要特判1不是素数。
判断素数函数:
int judge(ll x)
{
if(x==1) return 0;
if(x<=3) return 1;
if(x%2==0) return 0;
for(ll i=3;i<sqrt(x);i+=2)
if(x%i==0) return 0;
return 1;
}
⭐其他判断素数的更优方法(都是1e9范围):高效率判断素数总结
L1-033 出生年 (15 分)
利用vis数组标记出现过的数字最后累加即为出现过的不同数字个数(要注意高位为0的情况,cnt初始值为1并且后续判断到0也不用变化)。这题写得很快一直卡一个样例,de了十几分钟的bug发现我对题意有误解,y∈[1,3000],但并不意味着x也在这个范围,即x可以大于3000,所以只要把循环终点改为3333即可(这是最大的情况,即y=3000,n=1时)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int vis[11];
int judge(int y,int n)
{
int cnt=0,yy=y;
if(y<1000) cnt++;
while(y!=0)
{
int m=y%10;
if(m==0&&yy<1000) cnt=cnt;
else
{
cnt+=abs(vis[m]);
//cout<<yy<<" "<<m<<" vis="<<vis[m]<<" "<<cnt<<endl;
vis[m]=0;
}
y/=10;
}
if(cnt==n) return 1;
else return 0;
}
int main()
{
int y,n;
cin>>y>>n;
for(int i=y;i<=3333;i++)
{
memset(vis,-1,sizeof(vis));
if(judge(i,n))
{
printf("%d %04d",i-y,i);
break;
}
}
return 0;
}
L1-044 稳赢 (15 分)
尝试后发现自定义函数返回值类型还能选string的😁,越来越喜欢用string了,好香。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e4+5;
int k;
string win(char ch)
{
if(ch=='C') return "Bu";
else if(ch=='J') return "ChuiZi";
else if(ch=='B') return "JianDao";
}
int main()
{
cin>>k;
string s;
int t=0;
while(cin>>s)
{
if(s[0]=='E') break;
if(t==k)
{
cout<<s<<endl;
t=0;
}
else
{
cout<<win(s[0])<<endl;
t++;
}
}
return 0;
}
L1-046 整除光棍 (20 分)
因为求出来的数可能很大,所以不可能是通过s来求光棍数。那么就通过光棍数逐位增加的同时来一位位地求出s。其实相当于摆竖式的原理,从高位开始运算,除不尽就多加一位1,循环往复,直到正好整除为止。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
int x,s,n=0;
int main()
{
scanf("%d",&x);
int num=0,flag=0;
for(int i=1;;i++)
{
num=num*10+1;
if(num>=x)
{
s=num/x;
printf("%d",s);
flag=1;
}
else if(flag) printf("0");
num=num%x;
if(num==0)
{
printf(" %d",i);
break;
}
}
return 0;
}
L1-054 福到了 (15 分)
正序赋值后倒序输出,要注意getchar()的几个地方。模拟一下就知道满足倒序的下标对应的是: a [ i ] [ j ] a[ i ] [ j ] a[i][j] —> a [ n − i + 1 ] [ n − j + 1 ] a[ n-i+1 ] [ n-j+1 ] a[n−i+1][n−j+1] 。关于判断需不需要倒的话我是又遍历了一遍,可能有点麻烦,有好方法欢迎评论。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e4+5;
char a[105][105];
int main()
{
char ch;
int n;
cin>>ch>>n;
getchar();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j]=getchar();
if(a[i][j]!=' ') a[i][j]=ch;
}
getchar();
}
int flag=1;
for(int i=1;i<=n&&flag;i++) //判断需不需要倒
{
for(int j=1;j<=n;j++)
{
if(a[i][j]!=a[n-i+1][n-j+1])
{//一旦发现正反不同就标记并break
flag=0;
break;
}
}
}
if(flag) cout<<"bu yong dao le"<<endl;
for(int i=n;i>=1;i--) //倒序输出
{
for(int j=n;j>=1;j--) cout<<a[i][j];
cout<<endl;
}
return 0;
}
L1-058 6翻了 (15 分)
用 s t r i n g string string 的 e r a s e erase erase 函数来实现替换(删除后再跟加)。有一些细枝末节的地方要写得仔细一点,比如判断是否为 6 6 6 的起始位置或 6 6 6 的连续区间、 x i xi xi 是 b b b 字符串中的位置坐标所以不能直接记为 i i i 而应该是重新计算 b b b 的当前长度、以及删除时的区间坐标,最后几行有一句注释掉的可以用来debug,会清楚很多。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e4+5;
int main()
{
string a,b;
getline(cin,a);
int len=a.length(),t=0,flag=0,xi;
for(int i=0;i<=len;i++)
{
if(a[i]=='6')
{
if(t==0) //检测到起始情况
{
flag=1;
b+=a[i];
t++;
xi=b.length()-1; //记录6的起始位置
}
else if(flag) //当前为连续区间
{
b+=a[i];
t++;
}
}
else if(a[i]!='6')
{
if(flag)
{
flag=0; //记得初始化
if(t>3&&t<=9) //替换
{
b.erase(xi,xi+t);
b+='9';
}
else if(t>9) //替换
{
b.erase(xi,xi+t);
b+="27";
}
}
b+=a[i]; //不要忘记跟加这个不为6的字符
t=0; //不要忘记初始化
}
//cout<<"i="<<i<<" t="<<t<<" xi="<<xi<<" b="<<b<<endl;
}
cout<<b;
return 0;
}
L1-069 胎压监测 (15 分)
求最大值可以用max_element函数 ,例如a[0]~a[3]最大值 m a x x maxx maxx = a[ max_element( a , a+4 ) - a ]。
L1-064 估值一亿的AI核心代码 (20 分)
这题有点绕,要保持头脑清醒一点,合理安排好执行每种操作的先后顺序,剩下的就是基础问题和细节问题
① 去除空格(erase函数和isalnum函数实现)
②转换小写(需要特判独立的
“
I
”
“I”
“I” 的情况)
③替换“can you”和“could you”(find函数和replace函数实现)。这里要注意一个问题,不能直接换成“I can/could”,因为后面还要替换“I/me”这一类,会重复误操作。
④替换“I/me”(同理③)
⑤替换“?”和③中的人称
部分知识点补充:
①erase函数的三种用法(参考博客:传送门)
string s;
s.erase(i,n); 删除第i个开始的n个字符
s.erase(it); 删除迭代器it所指向的字符(即第it个字符)
s.erase(s.begin()+st,s.end()-ed); 保留前st个和后ed个,其余中间的删除
②isalnum函数(参考博客:传送门)
int isalnum(int x) 判断x是否为字母或数字,是就返回1,否就返回0。
③find函数(参考博客:①find详解②find避坑)
string s,str;
s.find(str); 在s字符串中查找str字符串,返回第一次找到的下标,找不到返回-1;
s.find(str,i); 在s字符串中第i个位置开始查找str字符串,返回第一次找到的下标,找不到返回-1;
s.find(str,i,j); 在s字符串中第i个位置开始查找str字符串的前j个子串,返回第一次找到的下标,找不到返回-1;
④replace函数(参考博客:传送门)
string s,str;
s.replace(i,len,str); 替换s字符串第i个位置开始长为len的子串为str;
s.replace(st,ed,str); 类似于上一种,但st和ed都是迭代器;
s.replace(i,len,n,ch); 替换s字符串第i个位置开始长为len的子串为n个ch;
s.replace(st,ed,n,ch); 替换s字符串区间为[st,ed]的子串为n个ch;(st和ed为迭代器)
s.replace(i,len1,str,j,len2); 将s的位置为[i,i+len1-1]的子串替换为str的位置为[j,j+len2-1]的子串;
AC代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e4+5;
int main()
{
int n;
cin>>n;
getchar();
while(n--)
{
string s,a;
getline(cin,s);
cout<<s<<endl<<"AI: ";
//transform(s.begin(),s.end(),s.begin(),::tolower);
while(s[0]==' ') s.erase(s.begin()); //开头多余空格
while(s[ s.length()-1 ]==' ') s.erase(s.end()-1); //结尾多余空格
for(int i=0;i<s.length();i++)
{
if(s[i]==' ') //去除中间多余空格
{
while(s[i+1]==' ') s.erase(s.begin()+i+1);
if(!isalnum(s[i+1])) s.erase(s.begin()+i);
}
}
for(int i=0;i<s.length();i++) //转换小写
if(s[i]>='A'&&s[i]<='Z'&&s[i]!='I') s[i]+=32;
for(int i=0;;i++) //替换can
{
i=s.find("can you",i);
if(i==-1) break;
if( ( !i || !isalnum(s[i-1]) )&&( i+7==s.length() || !isalnum(s[i+7]) ) )
s.replace(i,7,"Q can");
}
for(int i=0;;i++) //替换could
{
i=s.find("could you",i);
if(i==-1) break;
if( ( !i || !isalnum(s[i-1]) )&&( i+9==s.length() || !isalnum(s[i+9]) ) )
s.replace(i,9,"Q could");
}
for(int i=0;;i++) //替换I
{
i=s.find("I",i);
if(i==-1) break;
if( ( !i || !isalnum(s[i-1]) )&&( i+1==s.length() || !isalnum(s[i+1]) ) )
s.replace(i,1,"you");
}
for(int i=0;;i++) //替换me
{
i=s.find("me",i);
if(i==-1) break;
if( ( !i || !isalnum(s[i-1]) )&&( i+2==s.length() || !isalnum(s[i+2]) ) )
s.replace(i,2,"you");
}
for(int i=0;i<s.length();i++)
{
if(s[i]=='?') s[i]='!';
if(s[i]=='Q') s[i]='I';
}
cout<<s<<endl;
}
return 0;
}
L2-032 彩虹瓶 (25 分)
用堆栈模拟一下就行,注意一下now==num后栈顶元素可不可以继续取走,直到没有可取的为止(while实现)。这题模拟赛做到了,很有思路但是因为基础很差,堆栈的一些基本操作忘了,赛后看了眼笔记就过了,所以还是基础要补好,毕竟不能带纸质材料。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int maxn=1e5+5;
int n,m,k;
int main()
{
scanf("%d%d%d",&n,&m,&k);
while(k--)
{
stack<int>st;
int num=1,now,flag=1;
for(int i=1;i<=n;i++)
{
scanf("%d",&now);
if(now!=num)
{
st.push(now);
if(st.size()>m) flag=0;
}
else
{
num++;
while(!st.empty())
{
if(st.top()==num)
{
num++;
st.pop();
}
else break;
}
}
}
if(flag!=0&&st.empty()) printf("YES\n");
else printf("NO\n");
}
return 0;
}