比赛地址:https://ac.nowcoder.com/acm/contest/11231
A:
记得开long long!!!
在a,b化成2进制的过程中,可以用一个变量x,表示现在到了哪个数位,例如个位是1,十位是10,百位是100......
再用一个变量ans表示答案, ans每次就加上a % 2 * x或b % 2 * x。
时间复杂度:O(log a+log b)
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long a,b;
scanf("%lld%lld",&a,&b);
long long ans=0,x;
x=1;
while(1)
{
ans+=(a%2)*x;
a/=2;
x*=10;
if(a==0) break;
}
x=1;
while(1)
{
ans+=(b%2)*x;
b/=2;
x*=10;
if(b==0) break;
}
printf("%lld\n",ans);
return 0;
}B:
我们用a[i]表示第i个位置之前最多有多少个前导0,用b[i]表示第i个位置之前最近的非0的位置。
我们用O(n)复杂度枚举r的位置,因为l,r<=10^25,所以选出来的子段最长只有26,因此时间允许。
在程序中,我用i表示l,j表示r,每次判断当前子段是否满足条件,如果子段>R,则直接退出循环,如果满足条件,则将答案加上a[i]+1,因为前导0并不影响子段的大小,然后每次将i变为b[i]即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int a[maxn];//s[i]前有几个0
int b[maxn];//s[i]前最近的非0
string l,r,s;
int checkk(int ll,int rr)
{
if(rr-ll+1>r.size())
{
return 3;
}
else if(rr-ll+1==r.size())
{
for(int ii=0;ii<r.size();ii++)
{
if(r[ii]<s[ll+ii]) return 3;
else if(r[ii]>s[ll+ii]) break;
}
}
if(rr-ll+1<l.size())
{
return 1;
}
else if(rr-ll+1==l.size())
{
for(int ii=0;ii<l.size();ii++)
{
if(l[ii]>s[ll+ii]) return 1;
else if(l[ii]<s[ll+ii]) break;
}
}
return 2;
}
int main()
{
cin>>l>>r>>s;
int x=0,y=-1;
for(int i=0;i<s.size();i++)
{
a[i]=x;
b[i]=y;
if(s[i]=='0') x++;
else x=0,y=i;
}
long long ans=0;
for(int j=0;j<s.size();j++)
{
int i=j;
while(1)
{
if(i==-1) break;
int p=checkk(i,j);
if(p==3)
{
break;
}
else if(p==2)
{
ans+=a[i]+1;
i=b[i];
}
else
{
i=b[i];
}
}
}
printf("%lld\n",ans);
return 0;
}
京公网安备 11010502036488号