HDU 4669 Mutiples on a circle (DP , 统计)

来源:互联网 发布:海典软件 垃圾 编辑:程序博客网 时间:2024/05/06 18:07

转载请注明出处,谢谢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;    }


原创粉丝点击