hdu 5564 Clarke and digits

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=5564

-----------------------------------------------------------------------------------------

刚读完题目感觉像是数位DP,然而仔细看了数据范围后感觉很不可做。

与数位DP题目对比可以发现 此题数据范围要大一些,却没有对每一位进行限制

于是便可以愉快地进行矩阵乘法优化DP啦

如果矩阵构造(将递推式转换为矩阵形式)还不熟练的话 可以参考

挑战程序设计竞赛(第2版) 3.4.2节

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod = 1e9 + 7, L = 70 + 1;
int t, l, r, m;
long long raw[L][L], tmp[L][L], a[L][L], b[L][L], f[L];
long long ans1, ans2;
void mul(long long A[L][L], long long B[L][L])
{
    memset(tmp, 0, sizeof tmp);
    for(int i = 0; i < L; ++i)
        for(int j = 0; j < L; ++j)
        {
            for(int k = 0; k < L; ++k)
                tmp[i][j] += A[i][k] * B[k][j] % mod;
            tmp[i][j] %= mod;
        }
    for(int i = 0; i < L; ++i)
        for(int j = 0; j < L; ++j)
            A[i][j] = tmp[i][j];
}
long long solve(int lim)
{
    if(!lim)
        return 0;
    if(lim == 1)
        return 1;
    lim -= 2;
    for(int i = 0; i < L; ++i)
        for(int j = 0; j < L; ++j)
            a[i][j] = b[i][j] = raw[i][j];
    while(lim)
    {
        if(lim & 1)
            mul(a, b);
        mul(b, b);
        lim >>= 1;
    }
    long long tans = 0;
    for(int i = 0; i < L; ++i)
        tans += a[70][i] * f[i] % mod;
    return tans % mod;
}
int main()
{
    for(int i = 1; i <= 9; ++i)
        f[i * 7 + i % 7] = 1;
    f[70] = 1;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d%d", &l, &r, &m);
        memset(raw, 0, sizeof raw);
        for(int i = 0; i <= 9; ++i)
            for(int j = 0; j <= 9; ++j)
                if(i + j != m)
                {
                    for(int k = 0; k < 7; ++k)
                    {
                        raw[i * 7 + (k * 10 + i) % 7][j * 7 + k] = 1;
                        if((k * 10 + i) % 7 == 0)
                            ++raw[70][j * 7 + k];
                    }
                }
        raw[70][70] = 1;
        ans1 = solve(l - 1);
        ans2 = solve(r);
        printf("%lld\n", (ans2 - ans1 + mod) % mod);
    }
    return 0;
}

 

你可能感兴趣的:(hdu 5564 Clarke and digits)