• 【38.24%】【codeforces 621E】 Wet Shark and Blocks


    time limit per test2 seconds
    memory limit per test256 megabytes
    inputstandard input
    outputstandard output
    There are b blocks of digits. Each one consisting of the same n digits, which are given to you in the input. Wet Shark must choose exactly one digit from each block and concatenate all of those digits together to form one large integer. For example, if he chooses digit 1 from the first block and digit 2 from the second block, he gets the integer 12.

    Wet Shark then takes this number modulo x. Please, tell him how many ways he can choose one digit from each block so that he gets exactly k as the final result. As this number may be too large, print it modulo 109 + 7.

    Note, that the number of ways to choose some digit in the block is equal to the number of it’s occurrences. For example, there are 3 ways to choose digit 5 from block 3 5 6 7 8 9 5 1 1 1 1 5.

    Input
    The first line of the input contains four space-separated integers, n, b, k and x (2 ≤ n ≤ 50 000, 1 ≤ b ≤ 109, 0 ≤ k < x ≤ 100, x ≥ 2) — the number of digits in one block, the number of blocks, interesting remainder modulo x and modulo x itself.

    The next line contains n space separated integers ai (1 ≤ ai ≤ 9), that give the digits contained in each block.

    Output
    Print the number of ways to pick exactly one digit from each blocks, such that the resulting integer equals k modulo x.

    Examples
    input
    12 1 5 10
    3 5 6 7 8 9 5 1 1 1 1 5
    output
    3
    input
    3 2 1 2
    6 2 2
    output
    0
    input
    3 2 1 2
    3 1 2
    output
    6
    Note
    In the second sample possible integers are 22, 26, 62 and 66. None of them gives the remainder 1 modulo 2.

    In the third sample integers 11, 13, 21, 23, 31 and 33 have remainder 1 modulo 2. There is exactly one way to obtain each of these integers, so the total answer is 6.

    【题解】

    有b个盒子;
    每个盒子里都有n个数字;
    让你从每个盒子中都取出一个数字1..9;
    顺序组成长度为b的数字;
    问数字取余结果为k的数字个数;
    预处理出每个数字有多少个;
    如果b没那么大的话可以这样写;
    设dp[i][j]表示前i个数字组成的数取余结果为j的方案数
    dp[i+1][(j*10+t)%k]+=dp[i][j]*num[t];
    对于每一个转移;
    其实都是(j*10+t)%k += t这个数字的个数*dp[i][j];
    即每个转移都是一样的;
    则一开始预处理出一个初始矩阵a[i][j];
    这个矩阵表示的是
    一开始余数为i的时候利用1-9这几个数字到余数为j的方案数增加量;
    (还记得图论的从某个点到另外一个点恰好走k步的方案吗;http://blog.csdn.net/harlow_cheng/article/details/52615106我们一开始的初始矩阵也是任意两个点之间能否到达->即从i点到j点的方案增加量,(我们一开始是设为1表示联通的,那不正是方案增加量吗?)),这里也可以看成是知道任意两点之间(0..x-1)->(0..x-1)的连通关系,但是初始的时候任意两点联通对方案的增加量变成了一个可能大于1的数字);
    求矩阵的b次幂;
    最后的那个矩阵是为了加深理解;可以不用乘;->矩阵E->从0->0一开始的方案都为1,即都不变;
    乘一下就能够和答案联系在一起了;
    即从一开始取余为0->…->k
    最后输出ans[0][k];

    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <stack>
    #include <string>
    #define lson L,m,rt<<1
    #define rson m+1,R,rt<<1|1
    #define LL long long
    
    using namespace std;
    
    const int MAXMOD = 120;
    const LL MOD = 1e9+7;
    const int dx[5] = {0,1,-1,0,0};
    const int dy[5] = {0,0,0,-1,1};
    const double pi = acos(-1.0);
    
    struct abc
    {
        LL jz[MAXMOD][MAXMOD];
    };
    
    LL num[10];
    int n,b,k,x;
    LL f[MAXMOD];
    abc a;
    
    void input_LL(LL &r)
    {
        r = 0;
        char t = getchar();
        while (!isdigit(t)) t = getchar();
        LL sign = 1;
        if (t == '-')sign = -1;
        while (!isdigit(t)) t = getchar();
        while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
        r = r*sign;
    }
    
    void input_int(int &r)
    {
        r = 0;
        char t = getchar();
        while (!isdigit(t)) t = getchar();
        int sign = 1;
        if (t == '-')sign = -1;
        while (!isdigit(t)) t = getchar();
        while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
        r = r*sign;
    }
    
    abc jc(abc a, abc b)
    {
        abc c;
        for (int i = 0; i <= x-1; i++)
            for (int j = 0; j <= x-1; j++)
            {
                c.jz[i][j] = 0;
                for (int k = 0; k <= x-1; k++)
                    c.jz[i][j] = (c.jz[i][j] + a.jz[i][k] * b.jz[k][j])%MOD;
            }
        return c;
    }
    
    abc ksm(int x)
    {
        if (x == 1)
            return a;
        abc temp;
        temp = ksm(x>>1);
        temp = jc(temp,temp);
        if (x&1)
            temp = jc(temp,a);
        return temp;
    }
    
    int main()
    {
        //freopen("F:\rush.txt", "r", stdin);
        input_int(n);input_int(b);input_int(k);input_int(x);
        for (int i = 1;i <= n;i++)
        {
            int temp;
            input_int(temp);
            num[temp]++;
        }
        int now = 0;
        for (int i = 0;i<=x-1;i++)
            for (int j = 1;j <= 9;j++)
                a.jz[i][(i*10+j)%x]=(a.jz[i][(i*10+j)%x] + num[j])%MOD;
        abc ans = ksm(b);
        abc E;
        E.jz[0][0] = 1;
        ans = jc(E,ans);
        printf("%I64d
    ",ans.jz[0][k]);
        return 0;
    }
    
  • 相关阅读:
    javascript:void(0) 真正含义
    Memcache and Mongodb
    window下redis nosql初试
    CAS单点登录配置
    代理模式-你不并知道我的存在
    Netty In Action中文版
    【FastDev4Android框架开发】打造QQ6.X最新版本号側滑界面效果(三十八)
    同步并发操作之等待一次性事件
    关于Java特种兵下冊
    自己定义UISlider的样式和滑块
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632111.html
Copyright © 2020-2023  润新知