转载请注明出处,谢谢javascript:void(0)    by---cxlove

题意:给出一个环,每个点是一个数字,取一个子串,使得拼接起来的数字是K的倍数。

由于K不大,暂且不考虑环的话,那么dp[i][j]表示以i结尾的,模K为j的有多少个子串。

那么sigma (dp[i][0])便是不考虑环的答案。

考虑环的话,不知道别人怎么写的,我感觉我的写法不是很复杂。

环和情况1 和n肯定是必选的,那么便是一个前缀为后缀,一个后缀为前缀拼接而成。

所以枚举某个前缀,求出前缀模K,那么枚举后缀模K的值,通过之前已经预处理过的dp值,便可以求出有多少个后缀满足为K的倍数。

但是这样可能后缀和前缀重叠了,所以我们枚举前缀的同时,依次记录后缀不同模值的个数。

随着前缀的增长,这些后缀都是和前缀重叠的。

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <string>
#include <queue>
#include <cmath>
#include <algorithm>
#define lson step << 1
#define rson step << 1 | 1
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
const int N = 50005;
const int M = 205;
int n , k , a[N] ,l[N];
int dp[2][M] , prefix[N] , fac[N << 2] , suffix[N];
int cnt[M];
int cal (int x) {
    int cnt = 0;
    while (x) x /= 10 , cnt ++;
    return cnt;
}
int main () {
    #ifndef ONLINE_JUDGE
        freopen ("input.txt" , "r" , stdin);
        // freopen ("output.txt" , "w" , stdout);
    #endif
    while (scanf ("%d %d" , &n , &k) != EOF) {
        fac[0] = 1;
        for (int i = 1 ; i <= (n << 2) ; i ++)
            fac[i] = fac[i - 1] * 10 % k;
        for (int i = 1 ; i <= n ; i ++) {
            scanf ("%d" , &a[i]);
            l[i] = cal (a[i]);
        }
        for (int i = 0 ; i < 2 ; i ++) {
            for (int j = 0 ; j < k ; j ++)
                dp[i][j] = 0;
        }
        dp[1][a[1] % k] = 1;
        LL ans = dp[1][0];
        for (int i = 2 ; i <= n ; i ++) {
            for (int j = 0 ; j < k ; j ++)
                dp[i & 1][j] = 0;
            dp[i & 1][a[i] % k] ++;
            for (int j = 0 ; j < k ; j ++) {
                dp[i & 1][(j * fac[l[i]] + a[i]) %k] += dp[(i - 1) & 1][j];
            }
            ans += dp[i & 1][0];
        }
        prefix[0] = 0;suffix[n + 1] = 0;
        for (int i = 1 ; i <= n ; i ++) {
            prefix[i] = (prefix[i - 1] * fac[l[i]] + a[i]) % k;
        }
        int len = 0;
        for (int i = n ; i >= 1 ; i --) {
            suffix[i] = (a[i] * fac[len] + suffix[i + 1]) % k;
            len += l[i];
        }
        len = 0;
        for (int i = 0 ; i < k ; i ++)
            cnt[i] = 0;
        for (int i = 1 ; i <= n ; i ++) {
            cnt[suffix[i]] ++;
            len += l[i];
            int p = prefix[i];
            for (int j = 0 ; j < k ; j ++) {
                if ((j * fac[len] + p) % k) continue;
                ans += dp[n & 1][j] - cnt[j];
            }
        }
        printf ("%I64d\n" , ans);
    }
    return 0;    
}