PAT甲级--二分

A 1010 Radix

思路:
(1)n1:确定进制的数,n2:未确定进制的数
方便后面进行统一计算
(2)n1转换成10进制数,二分n2进制,将n2转换成十进制与n1进行比较,大了就把进制往小的方向调整,小了的话往大的调;如果相等,则找到进制,输出
Tips:本题的变量尽量都使用long long型
(坑:进制radix的范围超过int)

其他细节点请看注释,很详细的~~

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include<iostream>
#include<string>
using namespace std;
//const int maxn=10010;
long long map[256];
long long inf=((long long)1<<63-1);//long long 的最大值为2^63-1
char n1[22],n2[22],temp[22];
int tag,radix;

//初始化字符对应的整数,如果是直接大括号赋值,显得太麻烦了
void init()
{
    for(char c='0';c<='9';c++)
        map[c]=c-'0';
    for(char c='a';c<='z';c++)
        map[c]=c-'a'+10;
}

//将a转化为十进制,t为上界
long long convertnum10(char a[],long long radix,long long t)
{
    long long ans=0;
    int len=strlen(a);
    for(int i=0;i<len;i++)
    {
        ans=ans*radix+map[a[i]];
         //当把n1转化成10进制数时,判断是否超过long long的最大值
         //坑:数据默认保证n1转换成十进制时不超过longlong(但是题目没有说)
         //当寻找n2的上界时,判断是否超过n1的进制数
        if(ans<0||ans>t)
            return -1;
    }
    return ans;
}

//n2的十进制与n1的十进制数进行比较
int cmp(char n2[],long long radix,long long t)
{
    int len=strlen(n2);
    long long num=convertnum10(n2,radix,t);
    if(num<0)
        return 1;//溢出,肯定是n2>n1;(这个溢出,可能考虑不到)
    if(t>num)//n1较大,返回-1
        return -1;
    else if(t==num)//相等,返回0
        return 0;
    else
        return 1;//n2较大,返回1;
}

//二分法
long long binarysearch(char n2[],long long left,long long right,long long t)
{
    long long mid;
    while(left<=right)
    {
        mid=(left+right)/2;
        int flag=cmp(n2,mid,t);
        if(flag==0)
            return mid;
        else if(flag==-1)
            left=mid+1;
        else
            right=mid-1;
    }
    return -1;//解不存在
}

//求最大数位
int find_largest_digit(char n2[])
{
    int ans=-1;
    int len=strlen(n2);
    for(int i=0;i<len;i++)
    {
        if(map[n2[i]]>ans)
            ans=map[n2[i]];
    }
    return ans+1;
}

int main()
{
    init();
    cin>>n1>>n2>>tag>>radix;
    if(tag==2)//这里假设n1为进制已知的那个,方便后面的计算
    {
        strcpy(temp,n1);
        strcpy(n1,n2);
        strcpy(n2,temp);
    }
    long long t=convertnum10(n1,radix,inf);//将n1从radix进制转化成十进制
    //最小进制,就比如,如果数字里最大的是‘ z ',那么它的进制数就不可能小于36。
    //求出最大数位,那么进制数的底线就是最大数位+1
    long long low=find_largest_digit(n2);
    //设两个数为n1和n2,其中n1已知进制数,那么将其转换为十进制数为n1x,那么最大的进制数为n1x和最小进制数中大的那一个
    //因为取n1x是,基数取1,要是进制数再大,就根本取不到了
    //上界为下界与n1的十进制的较大值+1
    long long high=max(low,t)+1;
    long long ans=binarysearch(n2,low,high,t);//二分,基数的上限理论上可以是无穷大,所以用long long
    if(ans==-1)
        cout<<"Impossible";
    else
        cout<<ans;
    return 0;
}

A 1044 Shopping in Mars

思路:
(1)令sum[i]表示A[1]到A[i]的和值,计算连续子序列的和值,即可计算sum[j]-sum[i-1]
(2)sum[i]就是严格单调递增,就可采用二分法来做题

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

int main()
{
    int n,s,i,k=100000010;
    cin>>n>>s;
    sum[0]=0;//注意sum数组的值是从1开始有意义
    for(i=1;i<=n;i++)
    {
        scanf("%d",&sum[i]);
        sum[i]+=sum[i-1];
    }
    for(i=1;i<=n;i++)
    {
        int j=upper_bound(sum+i,sum+n+1,sum[i-1]+s)-sum;
        if(sum[j-1]-sum[i-1]==s)
        {
            k=s;
            break;
        }
        else if(j<=n&&sum[j]-sum[i-1]<k)
        {
            k=sum[j]-sum[i-1];
        }
    }
    for(i=1;i<=n;i++)
        {
            int j=upper_bound(sum+i,sum+n+1,sum[i-1]+k)-sum;
            if(sum[j-1]-sum[i-1]==k)
            {
                printf("%d-%d\n",i,j-1);
            }
        }
    return 0;
}

A 1048 Find Coins

思路:
(1)输入数组,排序
(2)题目目标:a[i]+a[j]=s;所以a[j]=s-a[i];
以i为循环变量,二分查找第一个满足条件的j的位置,找到后,输出i,j

#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,s,i,j;
    cin>>n>>s;
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    sort(a,a+n);
    for(i=0;i<n;i++)
    {
       j=lower_bound(a,a+n,s-a[i])-a;
       if(j!=i&&a[i]+a[j]==s)
       {
           printf("%d %d\n",a[i],a[j]);
           break;
       }
    }
    if(i==n)
        cout<<"No Solution";
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值