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;
}