比赛地址: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; }