HDU 4669 Mutiples on a circle (DP , 統計)

acm_cxlove發表於2013-08-29

轉載請註明出處,謝謝http://blog.csdn.net/ACM_cxlove?viewmode=contents    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;    
}


相關文章