题意:
输入一个只包含数字的字符串,求出是300的倍数的子串的个数(不同位置的0、00、000等都算,并考虑前导零的情况)。
sample input:
600
123000321013200987000789
sample output:
4
55
题解:
O(n)做法:遍历一遍,求前缀和sum取余3,统计sum的个数num[sum],遇到本位和下一位都是0,则把之前统计的个数加上,最后加上单独0的个数。
O(300n)DP做法:如下
官方题解:
Code:
O(n)做法如下:
/*6ms*/
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int M=1e5+5; 5 char s[M]; 6 int main() 7 { 8 while(~scanf("%s",s+1)) 9 { 10 int len=strlen(s+1),sum=0,num[3]={}; 11 ll cnt=0; 12 num[0]=1; 13 for(int i=1;i<=len;i++){ 14 sum=(sum+(s[i]-'0'))%3; 15 if(s[i]=='0'&&s[i+1]=='0'){ 16 cnt+=num[sum]; 17 } 18 if(s[i]=='0')cnt++; 19 num[sum]++; 20 } 21 printf("%lld\n",cnt); 22 } 23 return 0; 24 }
DP做法如下【O(300n)】:
/*224ms*/
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int M=1e5+5; 5 char s[M]; 6 int dp[M][302]; 7 int main() 8 { 9 while(~scanf("%s",s+1)) 10 { 11 memset(dp,0,sizeof(dp)); 12 dp[1][s[1]-'0']=1; 13 int len=strlen(s+1); 14 for(int i=2;i<=len;i++){ 15 dp[i][s[i]-'0']++; 16 for(int j=0;j<300;j++){ 17 int flag=(j*10+s[i]-'0')%300; 18 dp[i][flag]+=dp[i-1][j]; 19 } 20 } 21 ll ans=0; 22 for(int i=1;i<=len;i++) 23 ans+=dp[i][0]; 24 printf("%lld\n",ans); 25 } 26 return 0; 27 }