PAT乙级题解
1001 害死人不偿命的(3n+1)猜想
传送门
知识点:简单模拟
思路:判断奇偶,根据题意即可
参考代码:
点击查看代码
#include<iostream>
using namespace std;
int main()
{
int n,cnt=0;
cin>>n;
while(n!=1){
if(n%2)//奇数
n=(3*n+1);
n/=2;
cnt++;
}
cout<<cnt<<endl;
return 0;
}
1002 写出这个数
传送门
知识点:模拟,递归,映射
思路:
输入数据过大,无法用int或long long存储,只能用string;
遍历string,ch-'0'即可得到该位数字,将各位数字相加得到sum,100位数字相加数据小于1000,使用int存储;
将sum拆分为数组,然后遍历输出映射的拼音,数字与拼音的映射使用string数组即可。
参考代码:
点击查看代码
#include<iostream>
using namespace std;
string num[10]={"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
int cnt=0;
int a[110];
//将数x拆分为数组,递归
void fun(int x){
if(x>=10) fun(x/10);
a[cnt++]=x%10;
}
int main()
{
string st;
int sum=0;
cin>>st;
//各位数字相加
for(char ch:st)
sum+=(ch-'0');
fun(sum);
//按位输出各数字映射的拼音
for(int i=0;i<cnt;i++){
cout<<num[a[i]];
if(i!=cnt-1) cout<<" ";
}
cout<<endl;
return 0;
}
1003 我要通过!
传送么
知识点:模拟,找规律
思路:
根据题意可以得出;
1、不含有PAT以外的字符;
2、P、T有且仅有一个;
3、字符串的格式为xPA..ATx..x,PT之间的A个数与T后面x的个数相等,而x也是由A组成的字符串,以cnt0、cnt1、cnt2表示其中A的个数,cnt0*cnt1==cnt2;
4、PT之间至少有一个A
参考代码:
点击查看代码
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
while(n--){
string st;
cin>>st;
bool flag=true;
int cnt=0;
int cnt0=0,cnt1=0,cnt2=0;
int cntp=0,cntt=0;
for(char ch:st){
if(ch=='P'){
//记录P之前的A
cnt0=cnt;
cnt=0;
cntp++;
}
else if(ch=='A')
cnt++;
else if(ch=='T'){
//记录PT之间的A
cnt1=cnt;
cnt=0;
cntt++;
}
//不能含有PAT以外的字符
else flag=false;
}
//记录T之后的A
cnt2=cnt;
//P、T有且仅有一个
if(cntp!=1||cntt!=1) flag=false;
//PT之间至少有一个A,xPA..ATx..x
if(cnt1==0||cnt1*cnt0!=cnt2) flag=false;
if(flag==true) cout<<"YES";
else cout<<"NO";
if(n!=0) cout<<endl;
}
return 0;
}
1004 成绩排名
传送门
知识点:结构体,排序
思路:使用结构体存储数据,使用sort以成绩为基准来排序,输出最高和最低成绩
参考代码:
点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;
//使用结构体存储数据
struct STU{
int sorce;
string num;
string name;
};
STU stu[110];
bool cmp(STU A,STU B){
return A.sorce<B.sorce;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>stu[i].name>>stu[i].num>>stu[i].sorce;
}
//使用sort以成绩为基准来排序
sort(stu,stu+n,cmp);
//输出最高和最低成绩
cout<<stu[n-1].name<<" "<<stu[n-1].num<<endl;
cout<<stu[0].name<<" "<<stu[0].num<<endl;
return 0;
}
1005 继续(3n+1)猜想
传送门
知识点:模拟,排序
思路:每个数x,经过一步步计算到达1,途中标记每一个中间量,表示他们被遍历过,可以由前面的数推算得到;剩下没有被标记过的就是关键数,从大到小排序后输出
参考代码:
点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;
int a[110],b[110];
bool v[110];
//从大到小排序
bool cmp(int a,int b){
return a>b;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
int x=a[i];
while(x!=1){
if(x%2) x=(3*x+1);
x/=2;
//数据范围为1~100
if(x>100) continue;
//标记数字x被遍历
v[x]=true;
}
}
//将关键数存到到另一个数组,方便排序
int cnt=0;
for(int i=0;i<n;i++)
if(v[a[i]]==false)
b[cnt++]=a[i];
sort(b,b+cnt,cmp);
cout<<b[0];
for(int i=1;i<cnt;i++)
cout<<" "<<b[i];
cout<<endl;
return 0;
}
1006 换个格式输出整数
传送门
知识点:简单模拟
思路:分离百十个位上的数,按照题意输出
参考代码:
点击查看代码
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
//分离百十个上的数
int b=n/100,s=(n/10)%10,g=n%10;
for(int i=0;i<b;i++)
cout<<"B";
for(int i=0;i<s;i++)
cout<<"S";
for(int i=1;i<=g;i++)
cout<<i;
cout<<endl;
return 0;
}
1007 素数对猜想
传送门
知识点:模拟
思路:遍历所有差为2的数对,判断两个数是否都是素数
参考代码:
点击查看代码
#include<iostream>
using namespace std;
//判断素数
bool check(int x){
for(int i=2;i*i<=x;i++)
if(x%i==0)
return false;
return true;
}
int main()
{
int n,cnt=0;
cin>>n;
for(int i=3;i<=n-2;i++)
if(check(i)&&check(i+2))
cnt++;
cout<<cnt<<endl;
return 0;
}
1008 数组元素循环右移问题
传送门
知识点:数组
思路:将数组整体翻转,再将前半和后半数组分别翻转,可以达到右移效果
参考代码:
点击查看代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
//移动所有数字相当没动
m=m%n;
vector<int> a(n);
for(int i=0;i<n;i++)
cin>>a[i];
reverse(a.begin(),a.end());
reverse(a.begin(),a.begin()+m);
reverse(a.begin()+m,a.end());
cout<<a[0];
for(int i=1;i<n;i++)
cout<<" "<<a[i];
cout<<endl;
return 0;
}
1009 说反话
传送门
知识点:字符串
思路:使用string数组存储数据,reverse将数组翻转
参考代码:
点击查看代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
vector<string> words;
string w;
while(cin>>w)
words.push_back(w);
reverse(words.begin(),words.end());
cout<<words[0];
for(int i=1;i<words.size();i++)
cout<<" "<<words[i];
cout<<endl;
return 0;
}
1010 一元多项式求导
传送门
知识点:模拟
思路:根据题意求导就行,注意零多项式
参考代码:
点击查看代码
#include<iostream>
using namespace std;
int main()
{
int m,n;
cin>>m>>n;
//特判零多项式
if(n==0){
puts("0 0");
return 0;
}
if(m*n!=0)
cout<<m*n<<" "<<n-1;
while(cin>>m>>n){
if(m*n!=0)
cout<<" "<<m*n<<" "<<n-1;
}
return 0;
}
1011 A+B 和 C
传送门
知识点:数据范围
思路:int取值范围:-231~231-1;long long取值范围:-263~263-1
参考代码:
点击查看代码
#include<iostream>
using namespace std;
int main()
{
int T;
cin>>T;
for(int i=1;i<=T;i++){
cout<<"Case #"<<i<<": ";
long long a,b,c;
cin>>a>>b>>c;
if(a+b>c)
puts("true");
else puts("false");
}
return 0;
}
1012 数字分类
传送门
知识点:模拟
思路:不难发现,将数字对5取模就得到了分类,使用switch-case语句来更清楚的表达多分支;由于A4为小数,需要特判
关键信息:若分类之后某一类不存在数字,则在相应位置输出 N。
参考代码:
点击查看代码
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int n;
cin>>n;
int a[6]={0},cnt=0;
bool flag=true,flag2=false;//表示加,表示A2这组没有数字
for(int i=0;i<n;i++){
int x;
cin>>x;
switch(x%5){
case 0:
if(x%2==0) a[1]+=x;
break;
case 1:
flag2=true;
a[2]+=(flag?x:-x);
flag=!flag;
break;
case 2:
a[3]++;
break;
case 3:
cnt++;
a[4]+=x;
break;
case 4:
a[5]=max(a[5],x);
break;
}
}
cout<<fixed<<setprecision(1);
for(int i=1;i<=5;i++){
int t=a[i];
//A2的运算中有加有减,所以最终结果为0不能表示这类没有数字
if((i!=2&&t==0)||(i==2&&flag2==false))
cout<<"N";
else{
if(i==4)
cout<<double(t)/cnt;
else cout<<t;
}
if(i!=5) cout<<" ";
}
return 0;
}
1013 数素数
传送门
知识点:数学知识-素数
思路:先求出足够多的素数,然后输出;
参考代码:
点击查看代码
#include<iostream>
#include<vector>
using namespace std;
bool check(int x){
for(int i=2;i*i<=x;i++)
if(x%i==0)
return false;
return true;
}
int main()
{
vector<int> a;
a.push_back(0);//让数组从1开始存储
for(int i=2;i<2e5;i++)
if(check(i))
a.push_back(i);
int m,n;
cin>>m>>n;
for(int i=m;i<=n;i++){
cout<<a[i];
if((i-m)%10==9)
cout<<endl;
else if(i!=n) cout<<" ";
}
return 0;
}
1014 福尔摩斯的约会
传送门
知识点:模拟
思路:
第一个条件:第一对相同的大写英文字母,以大写字母来代指星期,那么只有'A'~'G'是有效的
第二个条件:第一对相同的字符,24小时以'0''9'和'A''N'来代指
第三个条件:第一对相同英文字母,不区分大小写
参考代码:
点击查看代码
#include<iostream>
using namespace std;
string d[7]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
bool check0(char ch){//判断是否为大写字母
return ch>='A'&&ch<='Z';
}
bool check1(char ch){//判断是否为数字
return ch>='0'&&ch<='9';
}
bool check2(char ch){//判断是否为小写字母
return ch>='a'&&ch<='z';
}
int main()
{
string s0,s1,t0,t1;
cin>>s0>>s1>>t0>>t1;
bool flag=false;
for(int i=0;i<s0.size()&&i<s1.size();i++){
//第二个条件:第一对相同的字符
if(flag&&s0[i]==s1[i]){
if(check1(s0[i])){
cout<<"0"<<s0[i]-'0'<<":";
break;
}
else if(s0[i]>='A'&&s0[i]<='N'){
cout<<s0[i]-'A'+10<<":";
break;
}
}
//第一个条件:第一对相同的大写英文字母
if(s0[i]==s1[i]&&s0[i]>='A'&&s0[i]<='G'){
cout<<d[s0[i]-'A']<<" ";
flag=true;//表示开始判断第二对
}
}
//第三个条件:第一对相同英文字母
for(int i=0;i<t0.size()&&i<t1.size();i++){
if(t0[i]==t1[i]&&(check0(t0[i])||check2(t1[i]))){
if(i<10)
cout<<"0"<<i;
else cout<<i;
break;
}
}
return 0;
}
1015 德才论
传送门
知识点:结构体排序
思路:根据题意来划分组;编写cmp函数用于排序,先以组别然后德分最后准考证据
参考代码:
点击查看代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct STU{
string num;//学号
int x,y;//德分,才分
int score;//总分
int group;//组别
};
vector<STU> stu;
bool cmp(STU a,STU b){
if(a.group!=b.group)
return a.group<b.group;
else if(a.score!=b.score)
return a.score>b.score;
else if(a.x!=b.x)
return a.x>b.x;
return a.num<b.num;
}
int main()
{
int n,l,h;
cin>>n>>l>>h;
for(int i=0;i<n;i++){
STU t;
int g;
cin>>t.num>>t.x>>t.y;
if(t.x<l||t.y<l) continue;
if(t.x>=h&&t.y>=h) g=1;
else if(t.x>=h) g=2;
else if(t.x>=t.y) g=3;
else g=4;
t.group=g;
t.score=t.x+t.y;
stu.push_back(t);
}
sort(stu.begin(),stu.end(),cmp);
cout<<stu.size()<<endl;
for(int i=0;i<stu.size();i++)
cout<<stu[i].num<<" "<<stu[i].x<<" "<<stu[i].y<<endl;
return 0;
}
1016 部分A+B
传送门
知识点:模拟
思路:遍历每一位数,记录目标数D出现次数cnt,根据目标数D和出现次数cnt构造P
参考代码:
点击查看代码
#include<iostream>
using namespace std;
//记录d在x中的出现次数
int fun(int x,int d){
int cnt=0;
while(x>1){
if(d==x%10) cnt++;
x/=10;
}
return cnt;
}
//构造cnt位的x
int p(int x,int cnt){
int ans=0;
for(int i=0;i<cnt;i++)
ans=ans*10+x;
return ans;
}
int main()
{
int a,da,b,db;
cin>>a>>da>>b>>db;
cout<<p(da,fun(a,da))+p(db,fun(b,db));
return 0;
}
1017 A除以B
传送门
知识点:高精度
思路:高精度除法的模板题
参考代码:
点击查看代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> dev(vector<int> &A,int b,int &r){
vector<int> C;
for(int i=A.size()-1;i>=0;i--){
r=r*10+A[i];
C.push_back(r/b);
r%=b;
}
//去除前导0
reverse(C.begin(),C.end());
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
int main()
{
string a;
int b;
vector<int> A;
cin>>a>>b;
//逆序输入、逆序输出,和其他高精度运算保持一致
for(int i=a.size()-1;i>=0;i--)
A.push_back(a[i]-'0');
//余数
int r=0;
vector<int> q=dev(A,b,r);
for(int i=q.size()-1;i>=0;i--) cout<<q[i];
cout<<" "<<r;
return 0;
}
1018 锤子剪刀布
传送门
知识点:映射,模拟
思路:将字符和数字做映射,‘BCJ’映射为‘012’;平局两字符相等,相减为0;甲胜的情况BC、CJ、JB相减为-1、-1、2,加3模3后都为2;甲负即乙胜的情况为两字符相减后加3模3为1;在判断胜负的过程中记录每种字符胜利的次数
参考代码:
点击查看代码
#include<iostream>
#include<map>
using namespace std;
map<char,int> h={{'B',0},{'C',1},{'J',2}};
char s[3]={'B','C','J'};
int j[3];//甲的胜、负、平
int x[3],y[3];//布,锤子,剪刀
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
char ch0,ch1;
cin>>ch0>>ch1;
int flag=(h[ch0]-h[ch1]+3)%3;
j[flag]++;
if(flag==2)//甲胜
x[h[ch0]]++;
else if(flag==1)//乙胜
y[h[ch1]]++;
}
cout<<j[2]<<" "<<j[0]<<" "<<j[1]<<endl;
cout<<j[1]<<" "<<j[0]<<" "<<j[2]<<endl;
char J='B',Y='B';
int num0=x[0],num1=y[0];
for(int i=1;i<=2;i++)
if(num0<x[i]){
num0=x[i];
J=s[i];
}
for(int i=1;i<=2;i++)
if(num1<y[i]){
num1=y[i];
Y=s[i];
}
cout<<J<<" "<<Y;
return 0;
}
1019 数字黑洞
传送门
知识点:模拟
思路:
将输入的数字拆分为数组,排一次升序一次降序,再转化为数字,作相减操作,差作为下次循环的输入数字;
判断循环结束条件为差为0或者6174,当升序降序得到的数字相同时差为0,也意味着原来的数字各位相同;
注意不可以在开头判断输入为6174,因为当输入为6174时也应该走一遍这个过程即7641 - 1467 = 6174
参考代码:
点击查看代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//将数字转化为数组
vector<int> fun0(int n){
vector<int> a;
while(n>0){
a.push_back(n%10);
n/=10;
}
//加前导0
if(a.size()<4){
while(a.size()<4)
a.push_back(0);
}
reverse(a.begin(),a.end());
return a;
}
//将数组转化为数字
int fun1(vector<int> a){
int res=0;
for(int num:a)
res=res*10+num;
return res;
}
bool cmp(int a,int b){
return a>b;
}
int main()
{
int n;
cin>>n;
while(true){
vector<int> x=fun0(n);
sort(x.begin(),x.end(),cmp);
int a=fun1(x);
reverse(x.begin(),x.end());
int b=fun1(x);
n=a-b;
printf("%04d - %04d = %04d\n",a,b,n);
if(n==0||n==6174) break;
}
return 0;
}
1020 月饼
传送门
知识点:结构体排序,贪心
思路:要想获取最大收益,那么在需求量固定的情况下,应该尽可能卖更贵即单价更高的;输入为总量和总价,算出单价,根据单价排降序
参考代码:
点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;
struct CAKE{
double stock,sell,unit;
};
CAKE cake[1010];
bool cmp(CAKE a,CAKE b){
return a.unit>b.unit;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>cake[i].stock;
for(int i=0;i<n;i++){
cin>>cake[i].sell;
cake[i].unit=cake[i].sell/cake[i].stock;
}
//贪心法,按照单价来排序,优先选最贵的
sort(cake,cake+n,cmp);
double ans=0;
for(int i=0;i<n;i++)
if(m>=cake[i].stock){
ans+=cake[i].sell;
m-=cake[i].stock;
}
else{
ans+=(m*cake[i].unit);
break;
}
printf("%.2f\n",ans);
return 0;
}
1021 个位数统计
传送门
知识点:模拟
思路:输入不超过1000的正整数,只能用string,遍历每一位记录数字出现的个数
参考代码:
点击查看代码
#include<iostream>
using namespace std;
//记录每个数字的个数
int a[10];
int main()
{
//位数<=1000;只能用string存储
string st;
cin>>st;
for(char ch:st)
a[ch-'0']++;
for(int i=0;i<=9;i++)
if(a[i]!=0)
cout<<i<<":"<<a[i]<<endl;
return 0;
}
1022 D进制的A+B
传送门
知识点:模拟,递归
思路:开始想的是进制转换,然后发现D进制的D如果很小的话,比如等于2,那么转换后的数字就没法用int存储了,只能用数组存储或者直接输出;显然边转换进制,边将每一位输出是方便的;在不知道数字的位数情况下,递归处理可以实现正着输出,或者先将每一位存在数组里再逆序输出
参考代码:
点击查看代码
#include<iostream>
using namespace std;
//输出x的d进制数,递归实现正向输出
void fun(int x,int d){
if(x<d){
cout<<x;
return;
}
fun(x/d,d);
cout<<x%d;
}
int main()
{
int a,b,d;
cin>>a>>b>>d;
fun(a+b,d);
return 0;
}
1023 组个最小数
传送门
知识点:模拟,贪心
思路:找到最小的非0数字当首位,剩下的按照0~9顺序输出即可
参考代码:
点击查看代码
#include<iostream>
using namespace std;
int a[10];
int main()
{
for(int i=0;i<=9;i++)
cin>>a[i];
//找到最小的非0数字当首位
int pre;
for(int i=1;i<=9;i++)
if(a[i]!=0){
pre=i;
a[i]--;
break;
}
cout<<pre;
for(int i=0;i<=9;i++)
for(int j=0;j<a[i];j++)
cout<<i;
return 0;
}
1024 科学计数法
传送门
知识点:模拟
思路:使用string存储;由于整数部分固定为1位,那么第0位是符号位,第1位是整数部分,第2位是小数点,第3e-1位是小数部分,第e位是E,第e+1位是符号位,第e+2最后位是指数;找到E的位置,设为数字e,用来划分数字部分和指数部分;将指数部分的字符串转换为数字;根据指数符号位分类讨论,为正小数点往后挪,为负小数点往前挪
参考代码:
点击查看代码
#include<iostream>
using namespace std;
int main()
{
string st;
cin>>st;
if(st[0]=='-')
cout<<'-';
//找到E的位置
int e=0;
for(int i=4;i<st.size();i++)
if(st[i]=='E'){
e=i;
break;
}
//确定指数
int cnt=0;
for(int i=e+2;i<st.size();i++)
cnt=cnt*10+(st[i]-'0');
if(st[e+1]=='+'){
cout<<st[1];
//e-3为小数部分的长度
//小数点挪的超过小数部分的长度,则不需要小数点,并且还要后面补0
if(cnt<e-3){
for(int i=0;i<cnt;i++)
cout<<st[i+3];
cout<<".";
for(int i=cnt+3;i<e;i++)
cout<<st[i];
}
else{
for(int i=3;i<e;i++)
cout<<st[i];
//输出多的零
for(int i=0;i<cnt-e+3;i++)
cout<<"0";
}
}
else{
if(cnt==0)
for(int i=1;i<e;i++)
cout<<st[i];
else{
cout<<"0.";
for(int i=0;i<cnt-1;i++)
cout<<"0";
cout<<st[1];
for(int i=3;i<e;i++)
cout<<st[i];
}
}
return 0;
}
1025 反转链表
传送门
知识点:链表,数组
思路:开始我是使用结构体搞链表的,但花里胡哨的搞不清楚了;后面我用vector来存储,使用reverse来反转也方便;开两个数组存储数据data和下一坐标next;输入是乱序的,需要按照起始点重新梳理一遍
参考代码:
点击查看代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<iomanip>
using namespace std;
const int N=100010;
int ne[N],da[N];
int main()
{
int st,n,k;
cin>>st>>n>>k;
for(int i=0;i<n;i++){
int addr;
cin>>addr;
cin>>da[addr]>>ne[addr];
}
//输入是乱序的
vector<int> list;
for(int i=st;i!=-1;i=ne[i])
list.push_back(i);
for(int i=0;i+k<=list.size();i+=k)
reverse(list.begin()+i,list.begin()+i+k);
for(int i=0;i<list.size();i++){
cout<<setw(5)<<setfill('0')<<list[i]<<' '<<da[list[i]]<<' ';
if(i!=list.size()-1)
cout<<setw(5)<<setfill('0')<<list[i+1]<<endl;
else puts("-1");
}
return 0;
}
1026 程序运行时间
传送门
知识点:模拟
思路:c2-c1得到时钟数,宰除以clk_tck得到运行时间;再转换为时分秒的形式,就是转换为60进制,注意四舍五入
参考代码:
点击查看代码
#include<iostream>
#include<cstdio>
using namespace std;
const int CLK_TCK=100;
int main()
{
int c1,c2;
scanf("%d%d",&c1,&c2);
int t=(c2-c1+50)/CLK_TCK;//四舍五入
int s=t%60,m=(t/60)%60,h=t/3600;
printf("%02d:%02d:%02d",h,m,s);
return 0;
}
1027 打印沙漏
传送门
知识点:模拟、找规律
思路:找规律推公式得到,n阶沙漏的符号个数为2nn-1;首先判断沙漏的阶数,然后根据阶数和符号打印沙漏,先打印上班的倒三角,再打印下班的去了尖的三角
参考代码:
点击查看代码
#include<iostream>
using namespace std;
void print(int n,char ch){
//输出前n行的倒三角
for(int i=0;i<n;i++){
//输出空格
for(int j=0;j<i;j++)
cout<<" ";
for(int j=0;j+2*i<2*n-1;j++)
cout<<ch;
cout<<endl;
}
for(int i=n-2;i>=0;i--){
for(int j=0;j<i;j++)
cout<<" ";
for(int j=0;j+2*i<2*n-1;j++)
cout<<ch;
cout<<endl;
}
}
int main()
{
int n;
char ch;
cin>>n>>ch;
for(int i=1;i<=30;i++)
if(n<2*i*i-1){
print(i-1,ch);
cout<<n-2*(i-1)*(i-1)+1;
break;
}
return 0;
}
1028 人口普查
传送门
知识点:结构体、排序、字符串
思路:首先生日以yyyy/mm/dd的格式输入,所以得要字符串转数字,将年月日信息提取出来;然后需要判断这些日期是否合理;将合理的数据放入数组中并排序;注意,当一个有效日期也没有的时候,需要输出0
参考代码:
点击查看代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct BIR{
string name;
int y,m,d;
};
//返回年长的
bool cmp(BIR a,BIR b){
if(a.y!=b.y)
return a.y<b.y;
else if(a.m!=b.m)
return a.m<b.m;
return a.d<b.d;
}
//判断日期是否合理
bool check(int y,int m,int d){
if(y>2014||y<2014-200)
return false;
else if(y==2014&&m>9)
return false;
else if(y==2014-200&&m<9)
return false;
else if(y==2014&&m==9&&d>6)
return false;
else if(y==2014-200&&m==9&&d<6)
return false;
return true;
}
//将字符串拆分为数字
void fun(string t,int &y,int &m,int &d){
int idx=0;
for(int i=0;i<4;i++)
y=y*10+(t[i+idx]-'0');
idx=5;
for(int i=0;i<2;i++)
m=m*10+(t[i+idx]-'0');
idx=8;
for(int i=0;i<2;i++)
d=d*10+(t[i+idx]-'0');
}
int main()
{
vector<BIR> bir;
int n;
cin>>n;
for(int i=0;i<n;i++){
string name,t;
cin>>name>>t;
int y=0,m=0,d=0;
fun(t,y,m,d);
if(check(y,m,d))
bir.push_back({name,y,m,d});
}
sort(bir.begin(),bir.end(),cmp);
int cnt=bir.size();
if(cnt!=0)
cout<<cnt<<" "<<bir[0].name<<" "<<bir[cnt-1].name;
//可能一个有效的日期都没有
else cout<<"0";
return 0;
}
1029 旧键盘
传送门
知识点:字符串、映射
思路:开始的想法(有问题):双指针,i和j同时遍历两条字符串,若遍历到的字符相同则跳过,i和j都往后走一位,不相同则输出第一条字符串的字符,并标记该字符为已输出,i往后走一位,
由于ASCII码只有128个,所以可以开一个数组来记录键位是否损坏或者是否输出过;先遍历第二个字符串,将遍历到的字符标记为未损坏;再遍历第一个字符串,输出损坏的并且未被输出过的键位,并在输出后标记为已输出
参考代码:
点击查看代码
#include<iostream>
using namespace std;
//ascii码总共128个
bool check[200];
int main()
{
string s,t;
cin>>s>>t;
//先遍历字符串t,标记好的键位
for(char ch:t){
if(ch>='a'&&ch<='z')
ch=char(ch-32);
check[ch]=true;
}
for(char ch:s){
if(ch>='a'&&ch<='z')
ch=char(ch-32);
if(check[ch]==false){
cout<<ch;
//标记已经输出过的键位
check[ch]=true;
}
}
return 0;
}
1030 完美数列
传送门
知识点:模拟、贪心、双指针
思路:开始的想法(有问题):双指针i和j,一前一后扫描数列,不符合条件则往里缩,贪心的选择缩的快的一边
首先将数列排序,快慢指针i和j,i和j之间的就是当前数列,i表示当前数列最小值,j向后扩张找到当前数列最大值
参考代码:
点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=100010;
LL a[N];
int main()
{
int n;
LL p;
cin>>n>>p;
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
int cnt=0;
for(int i=0;i<n;i++)
//j向后扩张找到以a[i]为最小值的数列的最大值a[j],cnt为j-i+1
for(int j=i+cnt;j<n;j++)
if(a[i]*p>=a[j])
cnt++;
else break;
cout<<cnt;
return 0;
}
1034 有理数四则运算
传送门
知识点:模拟、最大公约数
思路:
- 以分子分母的形式存储一个数,写个函数将这个数转化为题目要求的标准格式(负数要有括号、假分数形式--有整数部分和分数部分、当分母为0时输出Inf)
- 然后就是以分数形式来处理两个数的加减乘除
- 得到的也是分子分母的分数形式,再以标准格式输出
x=xa/xb;y=ya/yb;
加法:(xa*yb+xb*ya)/(ya*yb)
减法:(xa*yb-xb*ya)/(ya*yb)
乘法:(xa*ya)/(ya*yb)
除法:(xa*yb)/(ya*xb)
参考代码:
点击查看代码
#include<iostream>
using namespace std;
typedef long long LL;
LL gcd(LL a, LL b)//求最大公约数
{
return b ? gcd(b, a % b) : a;
}
void fun(LL a,LL b){
if(b==0){
cout<<"Inf";
return;
}
bool flag=(a<0)^(b<0);//当只有一个小于0时,结果为true,是负数
a=abs(a),b=abs(b);
//约分一下,将分子和分母化为最简
LL t=gcd(a,b);
a/=t,b/=t;
if(flag) cout<<"(-";
LL k=a/b;//k为整数部分
a%=b;
if(a==0){
cout<<k;
}
else{
if(k) cout<<k<<" ";
cout<<a<<"/"<<b;
}
if(flag) cout<<")";
}
int main()
{
LL xa,xb,ya,yb;
char ch;//读入分号
cin>>xa>>ch>>xb>>ya>>ch>>yb;
//加法
fun(xa,xb);
cout<<" + ";
fun(ya,yb);
cout<<" = ";
fun(xa*yb+xb*ya,xb*yb);
cout<<endl;
//减法
fun(xa,xb);
cout<<" - ";
fun(ya,yb);
cout<<" = ";
fun(xa*yb-xb*ya,xb*yb);
cout<<endl;
//乘法
fun(xa,xb);
cout<<" * ";
fun(ya,yb);
cout<<" = ";
fun(xa*ya,xb*yb);
cout<<endl;
//除法
fun(xa,xb);
cout<<" / ";
fun(ya,yb);
cout<<" = ";
fun(xa*yb,xb*ya);
cout<<endl;
return 0;
}