题目:C. The Number Of Good Substrings
题意:
01字符串中有多少子串满足其十进制数值等于该子串长度,子串可包含前导零算数值。
思路:
注意到字符串S<2e5,而=1024,那么=1024*1024>1e6,所以我们要计算的一个长度只用20位就足够了,这里我们用一个循环去扫数字1,用p记录它的第一个前导零的位置(也就是上一个计算的串的第一位的下一个),只要当前的计算的串数值小于等于总长度(包括前导零)即可ans++,因为前导零可以补足以达到(长度等于数值的)要求,则退出条件即为数值大于总长度。在代码中,总长度:(j-p+1),i用来扫到数字1作为计算的子串的开头,j往后移的过程中不断判断是否满足条件。同时注意二进制串的值的计算:val=val*2+a[j]-'0';
附:p是在两个i(i为1)之间的第一个0的位置,若此时上一个i后面也是1,那么j==p,会在if(val>j-p+1)判断处跳出(因为右边为1,左边由上一行的乘二至少为2)
代码:
#include<stdio.h>
#include<string.h>
int T,n,p,i,j,val,ans;
char a[200005];
int main(){
scanf("%d",&T);
while(T--){
scanf("%s",a);
n=strlen(a);
p=ans=0;
for(i=0;i<n;i++){
if(a[i]=='1'){
val=0;
for(j=i;j<n&&j<=i+20;j++){
val=val*2+a[j]-'0';//扫到的1以后的十进制值
if(val>j-p+1)break;//j-p+1为目前子串(包括前导零)的长度
else ans++;//val一定>j-i+1的长度,故只要<长度(括前导零)即可
//因为前导零可以匹配
}
p=i+1;//p为下一个可能的串的第一个前导零位置
}
}
printf("%d\n",ans);
}
return 0;
}