PAT甲级--数学

A 1008 Elevator

思路:
划水题~~
注意上楼下楼时间不一样就行了

**#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<string>
using namespace std;
const int maxn=100010;
int a[maxn];

int main()
{
    int n,i,sum=0;
    cin>>n;
    a[0]=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]>a[i-1])
        {
            sum+=(a[i]-a[i-1])*6+5;
        }
        else
        {
            sum+=(a[i-1]-a[i])*4+5;
        }
    }
    cout<<sum;
    return 0;
}

A 1049 Counting Ones

思路:
(1)记n的各个位从低到高分别为,第1位、第2位、第3位…
分别考虑各个位出现1时满足范围的数有多少个
(2)规律:
设当前处理至第k位,记left为第k位左边高位表示的数,now为第k位的数,right为右边低位表示的数,a为righ的位数
若now=0,则ans+=lefta;
若now=1,则ans+=left
a+right+1;
若now>1,则ans+=(left+1)*a;
具体规律推算,可以找一个例子自己推推

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<string>
using namespace std;
int main()
{
    int n,a=1,ans=0;
    int left,now,right;
    cin>>n;
    while(n/a!=0)
    {
        left=n/(a*10);
        now=n/a%10;
        right=n%a;
        if(now==0)
            ans+=left*a;
        else if(now==1)
            ans+=left*a+right+1;
        else
            ans+=(left+1)*a;
        a*=10;
    }
    cout<<ans;
    return 0;
}

A 1081 Rational Sum

思路:
这题还是得细心,有几个注意点
(1)两个分母相乘,可达到long long,所以数据取long long型
(2)必须在每一步加法后都进行约分,如果全部加完再约分,可能会溢出
(3)格式问题:带分数的整数和分数之间有一个空格
此题涉及的运算都可用函数模板:
1)求最大公约数

long long gcd(long long a,long long b)
{
    return b==0?a:gcd(b,a%b);
}

2)分数化简

fraction reduction(fraction result)
{
    if(result.down<0)//分母为负数,分子分母同时乘-1
    {
        result.up=-result.up;
        result.down=-result.down;
    }
    if(result.up==0)
    {
        result.down=1;
    }
    else
    {
        int d=gcd(abs(result.up),abs(result.down));
        result.up/=d;
        result.down/=d;
    }
    return result;
}

3)分数加法

fraction add(fraction f1,fraction f2)
{
    fraction result;
    result.up=f1.up*f2.down+f2.up*f1.down;
    result.down=f1.down*f2.down;
    return reduction(result);
}

4)分数输出

void showresult(fraction r)
{
    reduction(r);
    if(r.down==1)
        cout<<r.up;
    else if(abs(r.up)>r.down)
        cout<<r.up/r.down<<" "<<abs(r.up)%r.down<<"/"<<r.down;//负号在r.up/r.down已输出
    else
        cout<<r.up<<"/"<<r.down;
}

下面就是完整代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<string>
using namespace std;
//const int maxn=100010;

struct fraction
{
    long long up,down;
};

//求最大公约数
long long gcd(long long a,long long b)
{
    return b==0?a:gcd(b,a%b);
}

//分数化简
fraction reduction(fraction result)
{
    if(result.down<0)//分母为负数,分子分母同时乘-1
    {
        result.up=-result.up;
        result.down=-result.down;
    }
    if(result.up==0)
    {
        result.down=1;
    }
    else
    {
        int d=gcd(abs(result.up),abs(result.down));
        result.up/=d;
        result.down/=d;
    }
    return result;
}

//分数加法
fraction add(fraction f1,fraction f2)
{
    fraction result;
    result.up=f1.up*f2.down+f2.up*f1.down;
    result.down=f1.down*f2.down;
    return reduction(result);
}

//输出分数
void showresult(fraction r)
{
    reduction(r);
    if(r.down==1)
        cout<<r.up;
    else if(abs(r.up)>r.down)
        cout<<r.up/r.down<<" "<<abs(r.up)%r.down<<"/"<<r.down;//负号在r.up/r.down已输出
    else
        cout<<r.up<<"/"<<r.down;
}

int main()
{
    int n;
    cin>>n;
    fraction sum,temp;
    sum.up=0;
    sum.down=1;
    for(int i=0;i<n;i++)
    {
        scanf("%lld/%lld",&temp.up,&temp.down);
        sum=add(sum,temp);
    }
    showresult(sum);
    return 0;
}

A 1015 Reversible Primes

思路:
几个常用模板直接记下来,套用即可
1)素数判断

bool isprime(int n)
{
    if(n<=1)
        return false;
    int sqr=(int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++)
    {
        if(n%i==0)
            return false;
    }
    return true;
}

2)进制转换

int z[40]
int k=0;
 do
{
    z[k++]=n%d;
     n=n/d;
 }while(n!=0);

完整代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<math.h>
using namespace std;
const int maxn=100010;
int z[maxn];

bool isprime(int n)
{
    if(n<=1)
        return false;
    int sqr=(int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++)
    {
        if(n%i==0)
            return false;
    }
    return true;
}



int main()
{
    int n,d;
    while(~scanf("%d",&n))
    {
        if(n<0)
            break;
        scanf("%d",&d);
        if(!isprime(n))
            printf("No\n");
        else
        {
            int k=0;
            do
            {
                z[k++]=n%d;
                n=n/d;
            }while(n!=0);
            for(int i=0;i<k;i++)
                n=n*d+z[i];
            if(isprime(n))
                printf("Yes\n");
            else
                printf("No\n");
        }
    }

    return 0;
}

A 1078 Hashing

思路:
(1)判断素数,找出第一个比msize大的素数
(2)hash应用,判断冲突
(3)冲突解决:如果step从0~msize-1进行枚举仍然找不到位置,那么对于step大于等于msize来说也不可能找到位置(证明略)

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<math.h>
using namespace std;
const int maxn=100010;
bool hashtable[maxn]={false};

bool isprime(int n)
{
    if(n<=1)
        return false;
    int sqr=(int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++)
    {
        if(n%i==0)
            return false;
    }
    return true;
}

int main()
{
    int msize,n,temp;
    cin>>msize>>n;
    while(isprime(msize)==false)
    {
        msize++;
    }
    for(int i=0;i<n;i++)
    {
        scanf("%d",&temp);
        int k=temp%msize;
        if(hashtable[k]==false)
        {
            hashtable[k]=true;
            if(i==0)
                printf("%d",k);
            else
                printf(" %d",k);
        }
        else
        {
            int step;
            for(step=1;step<msize;step++)
            {
                int m=(temp+step*step)%msize;
                if(hashtable[m]==false)
                {
                    hashtable[m]=true;
                    printf(" %d",m);
                    break;//这个不能忘,不然出现死循环,最后一个测试点运行超时
                }
            }
            if(step>=msize)
            {
                if(i>0)
                    printf(" ");
                printf("-");
            }
        }
    }
    return 0;
}

A 1096 Consecutive Factors

思路:
这题的一个技巧点就是,寻找的连续整数其开头的第一个整数肯定不会超过 n \sqrt{n} n ,这样可以缩短遍历的范围

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<math.h>
using namespace std;
//const int maxn=100010;

int main()
{
    int  n;;
    cin>>n;
    int sqr=(int)sqrt(1.0*n);
    int ansi=0,anslen=0;
    for(int i=2;i<=sqr;i++)
    {
        int temp=1;
        for(int j=i;j<n;j++)
        {
            temp*=j;
            if(n%temp!=0)
                break;
            if(j-i+1>anslen)
            {
                ansi=i;
                anslen=j-i+1;
            }
        }
    }
    if(anslen==0)
        cout<<"1"<<endl<<n;
        else
        {
            cout<<anslen<<endl;
            for(int i=0;i<anslen;i++)
            {
                cout<<ansi+i;
                if(i<anslen-1)
                    cout<<"*";
            }
        }
    return 0;
}

A 1059 Prime Factors

思路:
对于一个正整数n来说,如果它存在【2,n】范围内的质因子,要么这些质因子全部小于等于 n \sqrt{n} n ,要么只存在一个大于 n \sqrt{n} n 的质因子。
(1)素数表的打印
(2)质因子分解

//打印素数表,模板
bool isprime(int n)
{
    if(n<=1)
        return false;
    int sqr=(int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++)
    {
        if(n%i==0)
            return false;
    }
    return true;
}

int prime[maxn];
int num=0;
void Find_Prime()
{
    for(int i=1;i<maxn;i++)
    {
        if(isprime(i))
        prime[num++]=i;
    }
}

完整代码:

#include <cstring>
#include<cstdio>
#include<algorithm>
#include<math.h>
#include <iostream>
using namespace std;
const int maxn=100010;

struct factor
{
    int x;
    int cnt;
}fac[11];

bool isprime(int n)
{
    if(n<=1)
        return false;
    int sqr=(int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++)
    {
        if(n%i==0)
            return false;
    }
    return true;
}

int prime[maxn];
int num=0;
void Find_Prime()
{
    for(int i=1;i<maxn;i++)
    {
        if(isprime(i))
        prime[num++]=i;
    }
}

int main()
{
    Find_Prime();
    int n,count=0;
    scanf("%d",&n);
    if(n==1) 
        printf("1=1");//特判1的情况,否则,无法输出1的结果
    else
    {
        printf("%d=",n);
        int sqr=(int)sqrt(1.0*n);
        for(int i=0;prime[i]<=sqr;i++)
        {
            if(n%prime[i]==0)
            {
                fac[count].x=prime[i];//记录质因子
                fac[count].cnt=0;
                while(n%prime[i]==0)//计算个数
                {
                    fac[count].cnt++;
                    n/=prime[i];
                }
                count++;
            }
            if(n==1) 
                break;//及时退出循环,1与任何大于1的数取余都是1
        }
        if(n!=1)//如果无法被根号n以内的质因子除尽
        {
            fac[count].x=n;//那么一定有一个大于根号n的质因子
            fac[count++].cnt=1;
        }
        for(int i=0;i<count;i++)
        {
            if(i>0)
                printf("*");
            printf("%d",fac[i].x);
            if(fac[i].cnt>1)
            {
                printf("^%d",fac[i].cnt);
            }
        }
    }
return 0;

}

A Have Fun with Numbers

思路:
(1)大整数乘法,高位数整数*低位数整数
(2)hash应用
该题又涉及函数模板(大整数乘法)
1)大整数结构体

struct bign
{
    int d[22];
    int len;
    bign()
    {
        memset(d,0,sizeof(d));
        len=0;
    }
};

bign change(char str[])
{
    bign a;
    a.len=strlen(str);
    for(int i=0;i<a.len;i++)
    {
        a.d[i]=str[a.len-1-i]-'0';
    }
    return a;
}

2)大整数乘法

bign multi(bign a,int b)
{
    bign c;
    int carry=0;
    for(int i=0;i<a.len;i++)
    {
        int temp=a.d[i]*b+carry;
        c.d[c.len++]=temp%10;
        carry=temp/10;
    }
    while(carry!=0)//和加法不一样,乘法的进位可能不止一位
    {
        c.d[c.len++]=carry%10;
        carry/=10;
    }
    return c;
}

完整代码

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<math.h>
using namespace std;
//const int maxn=100010;

struct bign
{
    int d[22];
    int len;
    bign()
    {
        memset(d,0,sizeof(d));
        len=0;
    }
};

bign change(char str[])
{
    bign a;
    a.len=strlen(str);
    for(int i=0;i<a.len;i++)
    {
        a.d[i]=str[a.len-1-i]-'0';
    }
    return a;
}

bign multi(bign a,int b)
{
    bign c;
    int carry=0;
    for(int i=0;i<a.len;i++)
    {
        int temp=a.d[i]*b+carry;
        c.d[c.len++]=temp%10;
        carry=temp/10;
    }
    while(carry!=0)//和加法不一样,乘法的进位可能不止一位
    {
        c.d[c.len++]=carry%10;
        carry/=10;
    }
    return c;
}

int main()
{
    char str[22];;
    cin>>str;
    bign a=change(str);
    bign mul=multi(a,2);
    int i=0;
    if(a.len!=mul.len)
        printf("No\n");
    else
    {
        int flag[10]={0};
        for(i=0;i<a.len;i++)
        {
            flag[a.d[i]]++;
            flag[mul.d[i]]--;
        }
        for(i=0;i<10;i++)
        {
            if(flag[i]!=0)
            {
                printf("No\n");
                break;
            }
        }
        if(i==10)
            printf("Yes\n");
    }
    for(i=mul.len-1;i>=0;i--)
        cout<<mul.d[i];
    return 0;
}

A 1024 Palindromic Number

思路:
和上一题相比,就多了一个判断回文串的函数,也就是从数组两端开始对比。
大整数加法和乘法其实很相似

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<math.h>
using namespace std;
const int maxn=100010;
char str[maxn];

struct bign
{
    int d[maxn];
    int len;
    bign()
    {
        memset(d,0,sizeof(d));
        len=0;
    }
};

bign change(char str[])
{
    bign a;
    a.len=strlen(str);
    for(int i=0;i<a.len;i++)
    {
        a.d[i]=str[a.len-1-i]-'0';
    }
    return a;
}

bign add(bign a,bign b)
{
    bign c;
    int carry=0;
    for(int i=0;i<a.len||i<b.len;i++)
    {
        int temp=a.d[i]+b.d[i]+carry;
        c.d[c.len++]=temp%10;
        carry=temp/10;
    }
    if(carry!=0)
    {
        c.d[c.len++]=carry;
    }
    return c;
}

bool judge(bign a)
{
    for(int i=0;i<a.len;i++)
    {
        if(a.d[i]!=a.d[a.len-1-i])
            return false;
    }
    return true;
}

void print(bign a)
{
    for(int i=a.len-1;i>=0;i--)
        printf("%d",a.d[i]);
    printf("\n");
}

int main()
{
    int n,i;
    cin>>str>>n;
    bign a=change(str);
    for(i=0;i<n;i++)
    {
        if(judge(a))
            break;
        bign b=a;
        reverse(b.d,b.d+b.len);
        a=add(a,b);
        
    }
    print(a);
    cout<<i;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值