zoukankan      html  css  js  c++  java
  • HDU 4669 Mutiples on a circle (DP , 统计)

    转载请注明出处,谢谢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
    " , ans);
        }
        return 0;    
    }


  • 相关阅读:
    Java并发编程:同步容器
    Java并发编程:深入剖析ThreadLocal
    使用jQuery开发一个响应式超酷整合RSS信息阅读杂志
    Javascript 严格模式
    参数传递的四种形式----- URL,超链接,js,form表单
    《CSS 设计指南》学习笔记 一
    【BootStrap】初步教程
    JavaScript日期对象使用总结
    Web前端知识技能大汇总
    浏览器 CSS Hack 收集
  • 原文地址:https://www.cnblogs.com/pangblog/p/3291983.html
Copyright © 2011-2022 走看看