题目列表
PAT1001 害死人不偿命的(3n+1)猜想
PAT1032挖掘机技术哪家强
特殊值
PAT1011 A+B 和 C
%I64d 和%lld 的区别
PAT 1016 部分A+B
10^9^
PAT 1026 程序运行时间
"%02d"
PAT 1046 划拳
PAT 1008 数组元素循环右移问题
取值范围,取余特性
PAT 1012 数字分类
".1f"
PAT 1018 锤子剪刀布
字符hash,固定长度循环使用求余,读取字符配合getchar()
PAT 1042 Shuffling Machine
特定数学规律的字符串数组表示
PAT 1046 Shortest Distance
解题思路要更加抽象概括
PAT 1065 A+B and C (64bit)
string 字符串数组 long long int 的相互转换
PAT1001 害死人不偿命的(3n+1)猜想
#include
#include
using namespace std;
int main(){
int n;
scanf("%d",&n);
int cnt=0;
while(n!=1){
if(n%2==0){
n/=2;
}else{
n=(3*n+1)/2;
}
cnt++;
}
printf("%d\n",cnt);
return 0;
}
PAT1032挖掘机技术哪家强
特殊值
分析
算法分析的做法:
先依次读入所有学校的数据,并累加,由于题目给出的是学校编号是连续的,所以从1到N开始遍历最大的值即可
我的做法:
在依次读入学校的数据的时候,就进行最大值的更新,这样的好处在于不需要再从头开始遍历,缺点就是增加了比较的次数
注意
这里面要额外考虑每个学校的分数都为0的情况,由于这里面保证了答案是惟一的,所以在用变量保留当前最大值的时候可以考虑使用新的sum>=sum的情况就进行更新
代码
#include
#include
using namespace std;
const int maxn=100000+5;
int a[maxn];
int main(){
int n;
scanf("%d",&n);
int index,sum=0;
for(int i=0;i
int t1,t2;
scanf("%d%d",&t1,&t2);
a[t1]+=t2;
if(a[t1]>=sum){
sum=a[t1];
index=t1;
}
}
printf("%d %d\n",index,sum);
return 0;
}
PAT1011 A+B 和 C
%I64d 和%lld 的区别
注意
这道题同样只是简单的模拟,int的数据范围是[-231, 231-1],而题目中给出的数据范围是[-231,231],所以在读取A,B,C的时候需要使用long long 这一数据类型
scanf(“lld”,&a);这样进行读取
知识点
%I64d 和%lld 的区别
long long定义方式可以用于gcc/g++,不受平台限制,但不能用于VC6.0。
__int64是Win32平台编译器64位长整型的定义方式,不能用于Linux。
“%lld”用于Linux i386平台编译器,”%I64d”用于Win32平台编译器。
cout只能用于C++编译,在VC6.0中,cout不支持64位长整型。
我现在常用c++,所以使用64位整数时,我使用long long 搭配着%lld
#include
#include
using namespace std;
int main(){
int n;
scanf("%d",&n);
for(int i=0;i
long long a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
printf("%s%d%s","Case #",i+1,": ");
if(a+b>c) printf("%s","true\n");
else printf("%s","false\n");
}
return 0;
}
PAT 1016 部分A+B
109
主要进行模拟即可(109在int数据的范围内)
#include
#include
using namespace std;
int getnum(int x,int t){
int sum=0;
while(x){
if(x%10==t){
sum=sum*10+t;
}
x/=10;
}
return sum;
}
int main(){
int a,d1,b,d2;
scanf("%d%d%d%d",&a,&d1,&b,&d2);
printf("%d\n",getnum(a,d1)+getnum(b,d2));
return 0;
}
PAT 1026 程序运行时间
“%02d”
这里面正常模拟即可
代码逻辑上没有问题,其实也可以再优化优化
#include
#include
using namespace std;
void printtime(int t){
if(t/10==0) printf("%s","0");
printf("%d",t);
}
int main(){
int t1,t2,time,t=0;
scanf("%d%d",&t1,&t2);
time=t2-t1;
if(time%100>=50) t=1;
time=time/100+t;
int h,m,s;
h=time/3600;
time=time%3600;
m=time/60;
time=time%60;
s=time;
printtime(h);
printf("%s",":");
printtime(m);
printf("%s",":");
printtime(s);
printf("%s","\n");
return 0;
}
算法分析中的参考代码:
我是自己额外单独判断了下是否满两位,不足的数字额外输出0,其实可以直接使用printf的格式控制“%02d”
PAT 1046 划拳
#include
#include
using namespace std;
int main(){
int n,a1,b1,a2,b2,r1=0,r2=0;
scanf("%d",&n);
while(n--){
scanf("%d%d%d%d",&a1,&b1,&a2,&b2);
int sum=a1+a2;
if(b1==sum){
if(b2!=sum){
r2++;
}
}else{
if(b2==sum)
r1++;
}
}
printf("%d %d\n",r1,r2);
return 0;
}
PAT 1008 数组元素循环右移问题
取值范围,取余特性
注意
我在进行实现的时候并没有考虑M有可能是大于N的,所以最开始提交的结果是部分正确。
还有一个规律是当字符串向右移动N位之后其实就是原本的字符串同时为了保证M始终是小于N的,所以令M=M%N。
题目中要求不使用额外的数组空间,其实就利用下标进行运算即可。
算法笔记中: 直接按照题目的含义进行输出结果
我的做法: 利用数学公式来进行计算即可
#include
#include
using namespace std;
const int maxn=100+5;
int a[maxn];
int n,m;
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i
scanf("%d",&a[i]);
}
m=m%n;
for(int i=0;i
printf("%d",a[(i+(n-m))%n]);
if(i!=n-1) printf("%s"," ");
else printf("%s","\n");
}
}
PAT 1012 数字分类
“.1f”
#include
#include
#include
using namespace std;
vector data[5];
bool f[5];
int main(){
int n;
long long sum1=0,max5=-1;
float sum3=0.0;
scanf("%d",&n);
data[0].push_back(0);
while(n--){
long long t;
scanf("%lld",&t);
switch(t%5){
case 0:{
if(t%2==0){
f[0]=true;
data[0][0]+=t;
}
};break;
case 1:{
f[1]=true;
if(data[1].size()%2==0){
data[1].push_back(t);
sum1+=t;
}else{
data[1].push_back(t);
sum1-=t;
}
};break;
case 2:{
f[2]=true;
data[2].push_back(t);
};break;
case 3:{
f[3]=true;
data[3].push_back(t);
sum3+=t;
};break;
case 4:{
f[4]=true;
if(t>max5){
max5=t;
}
};break;
}
}
if(f[0]) printf("%lld ",data[0][0]);
else printf("%s","N ");
if(f[1]) printf("%lld ",sum1);
else printf("%s","N ");
if(f[2]) printf("%lld ",data[2].size());
else printf("%s","N ");
if(f[3]) printf("%.1f ",sum3/data[3].size());
else printf("%s","N ");
if(f[4]) printf("%lld\n",max5);
else printf("%s","N\n");
return 0;
}
PAT 1018 锤子剪刀布
字符hash,固定长度循环使用求余,读取字符配合getchar()
算法笔记思路
我之前的思路也发现了BCJ,互相克制的巧合性是循环的,但是没有想到可以使用将BCJ 分贝对应0,1,2这样判断的时候,可以利用(K1+1)%3==K2来判断甲赢了乙
#include
#include
using namespace std;
int a[3];
int b[3];
int ac[3];
int bc[3];
int judge(char c1,char c2){
if(c1==c2){
return 0;
}else{
if(c1=='C'&&c2=='J'){
return 1;
}else if(c1=='J'&&c2=='B'){
return 1;
}else if(c1=='B'&&c2=='C'){
return 1;
}
}
return -1;
}
char list[3]={'B','C','J'};
int get_rank(char c1){
if(c1=='B') return 0;
else if(c1=='C') return 1;
else return 2;
}
int main(){
int n;
cin>>n;
char maxa='B',maxb='B';
int ma=0,mb=0;
while(n--){
char c1,c2;
cin>>c1>>c2;
int re=judge(c1,c2);
if(re==1){
a[0]++;
b[2]++;
ac[get_rank(c1)]++;
}else if(re==0){
a[1]++;
b[1]++;
}else{
a[2]++;
b[0]++;
bc[get_rank(c2)]++;
}
}
for(int i=0;i<3;i++){
if(ac[i]>ma)
{
ma=ac[i];
maxa=list[i];
}
if(bc[i]>mb){
mb=bc[i];
maxb=list[i];
}
}
for(int i=0;i<3;i++){
cout<
if(i!=2) cout<
else cout<
}
for(int i=0;i<3;i++){
cout<
if(i!=2) cout<
else cout<
}
cout<
return 0;
}
PAT 1042 Shuffling Machine
特定数学规律的字符串数组表示
在计算x/13的时候,如果没有x-1就会导致,最后一个数值会多1,具体是加一还是减一等调整,可以用特殊边界值来试一试
#include
#include
#include
#include
using namespace std;
int a[55];
int b[55];//存储当前已经经过处理后的数据
int put[55];//每次随机的位置
string data[55]={
"","S1","S2","S3","S4","S5","S6","S7","S8","S9","S10","S11","S12","S13",
"H1","H2","H3","H4","H5","H6","H7","H8","H9","H10","H11","H12","H13",
"C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13",
"D1","D2","D3","D4","D5","D6","D7","D8","D9","D10","D11","D12","D13",
"J1","J2"
};
int main(){
int k;
for(int i=0;i<55;i++){
a[i]=i;
b[i]=i;
put[i]=i;
}
cin>>k;
for(int i=1;i<=54;i++){
cin>>put[i];
}
while(k--){
for(int i=1;i<=54;i++){
a[put[i]]=b[i];
}
swap(b,a);
}
for(int i=1;i<=54;i++){
cout<
if(i!=54) cout<
else cout<
}
return 0;
}
PAT 1046 Shortest Distance
解题思路要更加抽象概括
我的思路
存储从左到右,1到每一个车站的距离,这样便于计算从左到右任意两车站之间的距离
例如:2到4之间的距离为(1,4)-(1,2)
由于整个路程是循环的,所以两个车站之间的距离要么为从左到右的距离,要么为绕了一圈再到该车站的距离,所以最终计算的结果就是这两个结果中的最小值
任意两个车站之间的距离为(x,y) 这里面默认y大于x
Dis1
利用1到两个不同车站之间的距离差计算
Dis1=(1,y)-(1,x)
Dis2
(1,n)-(1,y)+数据给出的最后一个车站到1的距离+(1,x)
Dis2=(y,n)+[n,1]+(1,x)=(1,n)-(1,y)+[n,1]+(1,x)
算法分析的思路
和我的类似,只不过算法分析看的更加抽象,直接将问题抽象看成求解min{dis[left,right],sum-dis[left,right]}
#include
#include
#include
using namespace std;
const int maxn=100000+5;
int oa[maxn];
int dis[maxn];
int main(){
int n,m;
cin>>n;
dis[1]=0;
for(int i=1,t;i<=n;i++){
cin>>t;
oa[i]=t;
dis[i+1]=dis[i]+t;
}
cin>>m;
for(int i=0;i
int t1,t2,re;
cin>>t1;
cin>>t2;
if(t2>t1) swap(t1,t2);
re=min(dis[t1]-dis[t2],dis[n]-dis[t1]+oa[n]+dis[t2]);
cout<
}
return 0;
}
PAT 1065 A+B and C (64bit)
string 字符串数组 long long int 的相互转换
2021/5/13
string 和字符串数组的转化
s1.c_str()
字符串数组和long long int 的转换
#include
x=atoll(chs);
String的相关操作
添加字符在尾部
(1) 常量字符:s1.append(ch);
(2) 变量字符:s1+=ch;
删除字符
s1.erase(pos,n);
即从给定起始位置pos处开始删除, 要删除字符的长度为n
部分正确的代码
最终放弃这个代码了,因为这个代码存在很大的问题,这个代码里面我模拟了一下大数的相加并进行比较,但我这里面相加只是考虑的是两个整数的相加的情形;
之所以想实现这个模拟的原因在于,题目中给出的最大正数的值为263超过了longlong的最大正数的值。由于已经实现了这个功能,所以我想从这个功能出发开始,额外判断一些特殊情况来“填补”我的代码,事实证明垃圾的代码就应该及时止损,一点点补充不是办法。
#include
#include
#include
#include
using namespace std;
int isgt(string s1,string s2,string s3){
string re="";
int a=0;
int i=s1.size()-1,j=s2.size()-1;
while(i>=0&&j>=0){
int x=s1[i]-'0'+s2[j]-'0'+a;
if(x>=10){
a=1;
re+=char('0'+x-10);
// re.append(char('0'+x-10));
}else{
a=0;
re+=char('0'+x);
// re.append(char('0'+x));
}
i--;
j--;
}
while(i>=0){
int x=s1[i]-'0'+a;
if(x>=10){
a=1;
re+=char('0'+x-10);
// re.append(char('0'+x-10));
}else{
a=0;
re+=char('0'+x);
// re.append(char('0'+x));
}
i--;
}
while(j>=0){
int x=s2[j]-'0'+a;
if(x>=10){
a=1;
re+=char('0'+x-10);
// re.append(char('0'+x-10));
}else{
a=0;
re+=char('0'+x);
// re.append(char('0'+x));
}
j--;
}
if(a==1)
re+=char('1');
// re.append(char('1'));
if(re.length()>s3.length()) return 1;
else if(re.length()
else{
reverse(re.begin(),re.end());
for(int k=0;k
if(re[k]>s3[k]){
return 1;
}else if(re[k]
return -1;
}
}
return 0;
}
}
bool judge(string s1,string s2,string s3){
if(s1=="9223372036854775808"&&s2[0]=='-'){
if(s3[0]=='-') return true;
else{
s2.erase(0,1);
return isgt(s2,s3,s1)<0;
}
}
return false;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
long long a,b,c;
string s1,s2,s3;
cin>>s1>>s2>>s3;
string ts1=s1,ts2=s2,ts3=s3;
a=atoll(s1.c_str());
b=atoll(s2.c_str());
c=atoll(s3.c_str());
cout<
if(a+b>c||(s1[0]!='-'&&s2[0]!='-'&&isgt(s1,s2,s3)>0)||judge(ts1,ts2,s3)||judge(s2,s1,s3)){
cout<
}else{
cout<
}
}
return 0;
}
分析算法笔记的思路:
可以发现本题的一个难点:除了在于知道计组内部原理会有正溢出和负溢出,还要清楚溢出后的数据范围,计算这个数据范围的时候由于long long有64位,所以在取余数的时候%264。
还要记住263这个数会在计算机表示中变成-263
#include
using namespace std;
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
long long a,b,c,res;
cin>>a>>b>>c;
res=a+b;
bool flag=false;
if(a>0&&b>0&&res<0) flag=true;
else if(a<0&&b<0&&res>=0) flag=false;
else if(res>c) flag=true;
else flag=false;
cout<
if(flag) cout<
else cout<
}
return 0;
}
重新编写的代码还是部分通过,说明最大值真的有263超出了long long范围,需要使用大数模拟