数学问题第一弹
PTA 乙级1003
1003 我要通过! (20 分)
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。
输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。
输入样例:
9
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
NO
没有读懂题目就下手,
过了样例的一半,还是误打误撞的那种,嘤~正确答案在下一版本
//1103
#include<bits/stdc++.h>
using namespace std;
int num=0;
bool judge(char ch[],int & num){
//APATA&&*PAT*
int p=0,a=0,t=0;
for(int i=0;i<strlen(ch);i++){
if(ch[i]!='P'&&ch[i]!='A'&&ch[i]!='T')return false;
if(p==0&&t==0&&ch[i]=='A')continue;
if(ch[i]=='P'){
p++;
if(p>1)return false;
}else if(ch[i]=='A'&&p==1&&t==0){
a++;
if(a>num+1)return false;
}else if(ch[i]=='T'){
if(p==0||a==0)return false;
t++;
if(t>1)return false;
}
}
if(a==num+1){
num++;
return true;
}
if(a==1)return true;
return false;
}
int n;
const int maxn=120;
char a[maxn];
int main(){
scanf("%d",&n);
while(n--){
scanf("%s",&a);
if(judge(a,num)){
printf("YES\n");
}else{
printf("NO\n");
}
}
return 0;
}
修正了一下对于原题的理解,现在可以通过所有的案例啦😊):
- mid*pre==end的字符数,其中mid\pre\end分别表示开头,pt中间以及pt之后的a/空字符个数
- 注意必须包含且仅包含pat三个字母
- 最后注意一下字符长度即可,虽然这里并没有挖坑~
AC代码如下:
//B1003
#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
char str[maxn];
int n;
bool isok(char str[],int len){
//计算开始、中间、结尾的A的个数
int pre_a=0,mid_a=0,end_a=0;
bool pflag=false,tflag=false;
for(int i=0;i<len;i++){
if(str[i]!='P'&&str[i]!='A'&&str[i]!='T'){
return false;
}
if(str[i]=='A'){
if(!pflag&&!tflag){
pre_a++;
}else if(pflag&&!tflag){
mid_a++;
}else if(pflag&&tflag){
end_a++;
}
}else if(str[i]=='P'){
if(pflag==false){
pflag=true;
}else return false;//出现了两次P
}else if(str[i]=='T'){
if(pflag==false)return false;//顺序错误
if(tflag)return false;//出现了两次T
else tflag=true;
}
}
if(mid_a==0||!tflag||!pflag)return false;
if(pre_a==0&&end_a==0)return true;
if(pre_a*mid_a==end_a)return true;
return false;
}
int main(){
scanf("%d",&n);
while(n--){
scanf("%s",&str);
if(isok(str,strlen(str))){
printf("YES\n");
}else printf("NO\n");
}
return 0;
}
数学问题第二弹
这个代码过了一半的样例,emm超时+错误,应该是有部分情况被我漏掉了,还有……解法比较笨拙22333😔
//1019
#include<bits/stdc++.h>
using namespace std;
char num[6];
int num1;
int num2;
int char2num(char num[],int n){
int sum=0;
for(int i=0;i<n;i++){
sum=sum*10+int(num[i]-'0');
}
return sum;
}
bool cmp(char a,char b){
return a>b;
}
void func(char num[],int n){
char cnum1[7];
char cnum2[7];
while(1){
sort(num,num+n);
strcpy(cnum1,num);//cnum1小的字符串
sort(num,num+n,cmp);
strcpy(cnum2,num);//cnum2大的字符串
num1=char2num(cnum1,n);//num1小的数字
num2=char2num(cnum2,n);//num2大的数字
printf("%04d - %04d = %04d\n",num2,num1,num2-num1);
if(num2-num1==0||num2-num1==6174)break;
int temp=num2-num1;
for(int i=0;i<n;i++){
num[i]=temp%10+'0';
temp/=10;
}
}
}
int main(){
scanf("%s",&num);
func(num,strlen(num));
return 0;
}
参考一篇博文改进,说实话,这题感觉不应该放在数学问题,应该属于cString库函数的熟练使用
- stoi->string类型转变为int数字类型
- str.insert(a,b,‘i’)在字符串str的第[a,b)号位置插入字符’i’
- to_string(a)将任意字符a转变为string类型
//1019
#include<iostream>
#include<string>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
bool cmp(char a,char b){
if(a>b)return true;
return false;
}
int main(){
string num1,num2,ans;
cin>>ans;
ans.insert(0,4-ans.length(),'0');//string前面插入字符
while(1){
num1=ans;
num2=ans;
sort(num1.begin(),num1.end(),cmp);//num1>num2
sort(num2.begin(),num2.end());
int a=stoi(num1);//string->int
int b=stoi(num2);
int c=a-b;
ans=to_string(c);//int->string
ans.insert(0,4-ans.length(),'0');
cout<<num1<<" - "<<num2<<" = "<<ans<<endl;
if(c==6174||c==0)break;
}
return 0;
}
数学问题第三弹
1049 数列的片段和 (20 分)
给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段。例如,给定数列 { 0.1, 0.2, 0.3, 0.4 },我们有 (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4) (0.2) (0.2, 0.3) (0.2, 0.3, 0.4) (0.3) (0.3, 0.4) (0.4) 这 10 个片段。
给定正整数数列,求出全部片段包含的所有的数之和。如本例中 10 个片段总和是 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0。
输入格式:
输入第一行给出一个不超过 10
5
的正整数 N,表示数列中数的个数,第二行给出 N 个不超过 1.0 的正数,是数列中的数,其间以空格分隔。
输出格式:
在一行中输出该序列所有片段包含的数之和,精确到小数点后 2 位。
输入样例:
4
0.1 0.2 0.3 0.4
输出样例:
5.00
给出1/2的解法,暂时还没有找到BUG,呜呜呜,不清楚哪里错了
//1049
#include<bits/stdc++.h>
using namespace std;
int n;
double num[1801010];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf",&num[i]);
}
double ans=0;
int right=1,left=n;
for(int i=1;i<=n;i++){
ans+=right*left*num[i];
right++;
left--;
}
printf("%.2f",ans);
return 0;
}
做了以下修改,改正了一个测试点,初步判定是进位的问题
double right=1.0,left=double(n);
//1049
#include<bits/stdc++.h>
using namespace std;
int n;
double num[1801010];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf",&num[i]);
}
double ans=0;
double right=1.0,left=double(n);
for(int i=1;i<=n;i++){
ans+=right*left*num[i];
right++;
left--;
}
printf("%.2f",ans);
return 0;
}
参考了大佬的代码刷PTA怎么能不提柳神,发现确实是使用double导致精度损失的问题,一个比较经典的解法是先将double类型的✖1000转化为long long类型,累计求和之后再➗1000.0的double类型,进位后保留两位有效数字输出
AC代码如下:
//1049
#include<bits/stdc++.h>
using namespace std;
int n;
typedef long long ll;
ll num[1801010];
double temp;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf",&temp);
num[i]=ll(temp*1000);
}
ll ans=0;
ll right=1,left=n;
for(int i=1;i<=n;i++){
ans+=right*left*num[i];
right+=1;
left-=1;
}
printf("%.2f",ans/1000.0);
return 0;
}
数学问题第四弹
这一题过于水汪汪,以至于让我怀疑……这个真的是甲级的难度吗?感觉可能就是为了给大家增加自信的题目额
PAT甲级1008
//甲级1008
#include<bits/stdc++.h>
using namespace std;
int num[200];
int n;
int count(int now,int next){
if(next>now){
return 5+(next-now)*6;
}else {
return 5+(now-next)*4;
}
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&num[i]);
}
int now=0;
int sum=0;
for(int i=0;i<n;i++){
sum+=count(now,num[i]);//计算当前层到目目标层耗费的时间
now=num[i];
}
printf("%d",sum) ;
return 0;
}
数学问题第五弹
PAT 甲级1049
暴力代码附上,会有两个样例运行超时😔
//1049
#include<bits/stdc++.h>
using namespace std;
long long int n;
long long int ans=0;
long long int count(long long num){
long long sum=0;
while(num){
if(num%10==1)sum++;
num/=10;
}
//printf("sum=%lld\n",ans);
return sum;
}
int main(){
scanf("%lld",&n);
long long i=1;
while(i<=n){
ans+=count(i);
i++;
}
printf("%lld",ans);
return 0;
}
改进后
【择日再补哈~】
数学问题第六弹
#include<bits/stdc++.h>
using namespace std;
int n,m;
int main(){
scanf("%d %d",&n,&m);
vector<int>v(n+1);
for(int i=1;i<=n;i++){
scanf("%d",&v[i]);
}
m=m%n;
int l=n-m+1;
bool flag=false;
for(int i=l;i<=n;i++){
if(flag==false){
flag=true;
printf("%d",v[i]);
continue;
}
printf(" %d",v[i]);
}
for(int i=1;i<l;i++){
if(flag==false){
flag=true;
printf("%d",v[i]);
continue;
}
printf(" %d",v[i]);
}
return 0;
}
数学问题第七弹
PTA甲级1081 分数加法
第一版:先附上展现思路但是运行没有结果的代码,这段代码没有结果的问题是,输入和处理数据放在同一个循环,在一轮迭代后来不及进行如此庞杂的计算
//1081
#include<bits/stdc++.h>
using namespace std;
//计算 分数的和
//计算最大公因数:辗转相除法
int gcd(int a,int b){
if(a<b){
swap(a,b);
}else{
if(b==0)return a;
return gcd(b,a%b);
}
}
char a[100];
//分数的计算
int in=0;
int sum2=0,sum1=0;
int main(){
int n;
scanf("%d",&n);
int temp1,temp2;
while(n--){
cin>>a;
sscanf(a,"%d/%d",&temp2,&temp1);
int max_in=gcd(temp2,temp1);
//第一个
if(sum1==0){
sum1=temp1/max_in;
sum2=temp2/max_in;
if(sum2/sum1){
in+=sum2/sum1;
sum2-=sum1*(sum2/sum1);
}
}
//第二个
else{
temp2=sum2*temp1+sum1*temp2;
temp1=sum1*temp1;
max_in=gcd(temp2,temp1);
sum2=temp2/=max_in;
sum1=temp1/=max_in;
if(sum2/sum1){
in+=sum2/sum1;
sum2-=sum1*(sum2/sum1);
}
}
}
if(in){
printf("%d %d/%d",in,sum2,sum1);
}else{
printf("%d/%d",sum2,sum1);
}
return 0;
}
第二版:
- 修改了输入和数据处理部分,将二者分开;
- 修改了欧几里得算法,用迭代代替递归后,解决了超时的问题;
但是仍然有一个样例没有过
检查
#include<bits/stdc++.h>
using namespace std;
int n;
char a[100];
//辗转相除法
int gcd(int m,int n){
if(m>=n)swap(m,n);
int r=m;
while(r!=0)
{
r=m%n;
m=n;
n=r;
}
return m;
}
int in=0,sum2=0,sum1=0;
int maxc;
int main(){
scanf("%d",&n);
vector<int>temp1(n);
vector<int>temp2(n);
for(int i=0;i<n;i++){
cin>>a;
sscanf(a,"%d/%d",&temp2[i],&temp1[i]);
}
for(int i=0;i<n;i++){
if(i==0){
maxc=gcd(temp2[i],temp1[1]);
in+=temp2[i]/temp1[i];
sum2=temp2[i]/maxc;
sum1=temp1[i]/maxc;
sum2-=(sum2/sum1)*sum1;
continue;
}else{
sum2=temp2[i]*sum1+temp1[i]*sum2;
sum1=temp1[i]*sum1;
in+=sum2/sum1;
maxc=gcd(sum1,sum2);
sum1/=maxc;
sum2/=maxc;
sum2-=(sum2/sum1)*sum1;
}
}
if(in&&sum2){
printf("%d %d/%d",in,sum2,sum1);
}else if(sum2){
printf("%d/%d",sum2,sum1);
}else if(in){
printf("%d",in);
}else{
printf("0");
}
return 0;
}
终于AC啦!感觉自己写的好处就是提高了自己找BUG的能力呢😃
- 本来gcd函数里加上swap判断是为了减小时间损耗,结果忘记有负数,所以这样写在输入-4/2 4/2会死循环,呜呜呜!
- 输出的时候需要配注意,整数或者分子部分为0的时候就不输出啦,当然都为零的时候需要输出0
- 最后复习了一下sscanf()
- 最后,虽然下面代码可以过样例,但是测试点中没有考虑输出-2/-1 这种情况等等,所以严谨的话还是得改改的,留给大家啦😄
//1081
#include<bits/stdc++.h>
using namespace std;
int sum2=0,sum1=1;//分子、分母
int in;//整数部分
char ch[100];
//获取a,b的最大公因数
int gcd(int a,int b){
//printf("%d和%d",a,b);
int temp;
//if(a<b)swap(a,b);
while(b!=0){
temp=b;
b=a%b;
a=temp;
}
//printf("公因数%d\n",a);
//4、2
return a;
}
//计算两个分数的加法
void ADD(int a2,int a1){
//a2分子,a1分母
int fenzi=sum2*a1+sum1*a2;
int fenmu=sum1*a1;
int maxc=gcd(fenzi,fenmu);
fenzi/=maxc;
fenmu/=maxc;
in+=fenzi/fenmu;
sum1=fenmu;
sum2=fenzi-(fenzi/fenmu)*fenmu;
}
int main(){
int n;
scanf("%d",&n);
vector<int>temp2(n);
vector<int>temp1(n);
for(int i=0;i<n;i++){
cin>>ch;
sscanf(ch,"%d/%d",&temp2[i],&temp1[i]);
}
for(int i=0;i<n;i++){
ADD(temp2[i],temp1[i]);
}
if(in&&sum2){
printf("%d %d/%d",in,sum2,sum1);
}else if(in){
printf("%d",in);
}else if(sum2){
printf("%d/%d",sum2,sum1);
}else{
printf("0");
}
return 0;
}
数学问题第八弹
PTA甲级1088,分数四则运算进阶
AC😳代码如下
其实做完了上一题,这题反而简单
主要是注意输出格式,俺是踩雷了好几次
最后,给出俺找BUG时候的样例:
输入:-1/5 -1/4
输出
(-1/5) + (-1/4) = (-9/20)
(-1/5) - (-1/4) = 1/20
(-1/5) * (-1/4) = 1/20
(-1/5) / (-1/4) = 4/5
//1088
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char ch1[100];
char ch2[100];
ll gcd(ll a,ll b){
ll temp;
while(b!=0){
temp=b;
b=a%b;
a=temp;
}
return a;
}
void change(ll fenzi,ll fenmu){
//格式化
if(fenmu==0){
printf("Inf");
return;
}
ll maxc=gcd(fenzi,fenmu);
ll n=fenzi/fenmu;
fenzi/=maxc;
fenmu/=maxc;
fenzi%=fenmu;
if(n<0){
if(fenzi==0)
printf("(%lld)",n);
else{
printf("(%lld %lld/%lld)",n,abs(fenzi),abs(fenmu));
}
}else if(n==0){
if(fenzi==0)
printf("%lld",n);
else if(fenmu>0&&fenzi>0){
printf("%lld/%lld",abs(fenzi),abs(fenmu));
}else{
printf("(-%lld/%lld)",abs(fenzi),abs(fenmu));
}
}else{
if(fenzi==0)
printf("%lld",n);
else{
printf("%lld %lld/%lld",n,abs(fenzi),abs(fenmu));
}
}
}
void DO(ll fenzi1,ll fenmu1,ll fenzi2,ll fenmu2){
//ADD
change(fenzi1,fenmu1);
printf(" + ");
change(fenzi2,fenmu2);
printf(" = ");
change(fenzi1*fenmu2+fenzi2*fenmu1,fenmu1*fenmu2);
printf("\n");
//SUB
change(fenzi1,fenmu1);
printf(" - ");
change(fenzi2,fenmu2);
printf(" = ");
change(fenzi1*fenmu2-fenzi2*fenmu1,fenmu1*fenmu2);
printf("\n");
//MUL
change(fenzi1,fenmu1);
printf(" * ");
change(fenzi2,fenmu2);
printf(" = ");
change(fenzi1*fenzi2,fenmu1*fenmu2);
printf("\n");
//DIV
change(fenzi1,fenmu1);
printf(" / ");
change(fenzi2,fenmu2);
printf(" = ");
change(fenzi1*fenmu2,fenmu1*fenzi2);
}
ll fenmu1,fenzi1,fenmu2,fenzi2;
int main(){
cin>>ch1>>ch2;
sscanf(ch1,"%lld/%lld",&fenzi1,&fenmu1);
sscanf(ch2,"%lld/%lld",&fenzi2,&fenmu2);
DO( fenzi1, fenmu1, fenzi2, fenmu2);
return 0;
}