CodeChef 3-Palindromes(Manacher+dp)
3-Palindromes |
All submissions for this problem are available.
Read problems statements in Mandarin Chinese and Russian as well.
Mike likes strings. He is also interested in algorithms. A few days ago he discovered for himself a very nice problem:
You are given a digit string S. You need to count the number of substrings of S, which are palindromes.
Do you know how to solve it? Good. Mike will make the problem a little bit more difficult for you.
You are given a digit string S. You need to count the number of substrings of S, which are palindromes without leading zeros and can be divided by 3 without a remainder.
A string is a palindrome if it reads the same backward as forward. A string is a palindrome without leading zeros if it reads the same backward as forward and doesn't start with symbol '0'. A string is a digit string, if it doesn't contain any symbols except '0', '1', '2', ..., '9'.
Please, note that you should consider string "0" as a palindrome without leading zeros.
Input
The first line of the input contains a digit string S.
Output
Your output should contain the only integer, denoting the number of substrings of S, which are palindromes without leading zeros and can be divided by 3 without a remainder.
Constraints
1 ≤ |S| ≤ 1 000 000
Example
Input: 1045003 Output: 4
Explanation
In the example you should count S[2..2] = "0", S[5..5] = "0", S[6..6] = "0" and S[7..7] = "3".
给出一个数字串。
问有多少个子串既是回文串也能被3整除~
先用Manacher处理好串的回文串长度。
然后用一个数组 cnt[i][j] 表示sigma( 1 ~ i-1 到i 的数 ) %3 == j 串的个数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long LL ; typedef pair<LL,LL> pii; #define X first #define Y second const int N = 2000010; char Ma[N] , s[N]; int Mp[N] , len ; void Manacher( char s[] , int len ) { int l = 0 ; Ma[l++] = '$' ; Ma[l++] = '#' ; for( int i = 0 ; i < len ; ++i ) { Ma[l++] = s[i]; Ma[l++] = '#' ; } Ma[l] = 0 ; int mx = 0 , id = 0 ; for( int i = 0 ; i < l ; ++i ) { Mp[i] = mx>i?min(Mp[2*id-i],mx-i):1; while( Ma[i+Mp[i]] == Ma[i-Mp[i]] ) { Mp[i]++; } if( i + Mp[i] > mx ) { mx = i + Mp[i]; id = i ; } } } bool is_dig( char op ) { if( op >= '0' && op <= '9' ) return true ; return false ; } LL cnt[N][3] , sum[N] ; void Run() { int n = strlen(s) ; Manacher(s,n); len = 2 * n + 2 ; memset( sum , 0 , sizeof sum ); memset( cnt , 0 , sizeof cnt ); for( int i = 1 ; i < len ; ++i ){ sum[i] = sum[i-1]; if( is_dig(Ma[i]) ) sum[i] += ( Ma[i] - '0' ); } for( int i = 2 ; i < len ; ++i ) { if( !is_dig(Ma[i]) || Ma[i] == '0' ) { for( int j = 0 ; j < 3 ; ++j ) cnt[i][j] = cnt[i-1][j]; } else { int x = Ma[i] - '0' ; for( int j = 0 ; j < 3 ; ++j ) { int _j = (j+x)%3; cnt[i][_j] += cnt[i-1][j] ; } cnt[i][x%3]++; } } LL ans = 0 ; for( int i = 2 ; i < len ; ++i ) { int x = 0 , tmp = sum[i-1] - sum[i-Mp[i]] ; if( is_dig(Ma[i]) ) { x = Ma[i] - '0' ; if( x % 3 == 0 ) ans++ ; } for( int j = 0 ; j < 3 ; ++j ) { if( ( 2*j + x )%3 == 0 ) { ans += cnt[i-1][j]; for( int z = 0 ; z < 3 ; ++z ) if( (z+tmp)%3 == j ){ ans -= cnt[i-Mp[i]][z]; } } } } printf("%lld\n",ans); } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL int _ , cas = 1 ; while( scanf("%s",s) != EOF )Run(); }