CodeChef 3-Palindromes(Manacher+dp)

3-Palindromes

 
Problem code: PALIN3
 

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 串的个数。

 

#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();
}
View Code

 

posted @ 2015-02-22 12:58  hl_mark  阅读(216)  评论(0编辑  收藏  举报