• HDU 4507 吉哥系列故事——恨7不成妻 数位DP


    这个不是求的数量,而是求平方和,所以记忆化的时候不能像以前那样无脑的来。

    先来看简单的情况,如果是求和,应该怎么搞。

    假如我现在搜索到第3位,一共有5位,情况应该是这样的XXiXX,注意后面的X和前面的X都是不确定的,转移的时候应该是i * 10^(5-3) * (能满足的条件的数的数量) + sigma((每个分支下面满足条件的数量)* (分支和))这样的形式,然后再返回到上一层。这样子就可以记忆化了。但是除了要统计数量,还要统计和。

    那么这里要统计平方和的话,如果还是上面这种情况,根据(a + b)^2 = a^2 + 2*a*b + b^2可以得出(i * 10^(5 - 3))^2 * (能满足的条件的数的数量) + 2 * sigma((每个分支下面满足条件的数量)*(分支和)) + sigma(分支平方和)。所以出了要维护分支和,还要维护分支平方和和数量。

    真鬼畜

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <climits>
    #include <string>
    #include <iostream>
    #include <map>
    #include <cstdlib>
    #include <list>
    #include <set>
    #include <queue>
    #include <stack>
    
    using namespace std;
    
    typedef long long LL;
    const int maxn = 20;
    const LL MOD = 1e9 + 7;
    int lim[maxn],len = 0;
    LL p10[maxn] = {1};
    
    struct EE {
        LL sqsum,sum,cnt;
        bool vis;
        EE(LL sqsum = 0,LL sum = 0,LL cnt = 0):sqsum(sqsum),sum(sum),cnt(cnt),vis(0) {}
    };
    
    EE f[maxn][10][10];
    
    void getlim(LL num) {
        len = 0;
        memset(lim,0,sizeof(lim));
        while(num) {
            lim[len++] = num % 10;
            num /= 10;
        }
    }
    
    EE dfs(int now,int bitsum,int rest,int bound,LL num) {
        if(now == 0) {
            if(bitsum % 7 == 0 || rest % 7 == 0) return EE(0,0,0);
            return EE(0,0,1);
        }
        EE &note = f[now][bitsum][rest];
        if(note.vis && !bound) return note;
        int m = bound ? lim[now - 1] : 9;
        EE ret(0,0,0);
        for(int i = 0;i <= m;i++) {
            if(i == 7) continue;
            int nbitsum = (bitsum + i) % 7;
            int nrest = (rest * 10 + i) % 7;
            int nbound = (i == m && bound);
            EE nret = dfs(now - 1,nbitsum,nrest,nbound,num * 10 + i);
            LL ff = p10[now - 1] * i % MOD;
            ret.cnt = (nret.cnt + ret.cnt) % MOD;
            ret.sum = ((nret.cnt * ff % MOD + nret.sum) % MOD + ret.sum) % MOD;
            ret.sqsum = ((nret.cnt * ff % MOD * ff % MOD + nret.sqsum) % MOD + 2 * ff % MOD * nret.sum % MOD + ret.sqsum) % MOD ;
        }
        if(!bound) note = ret,note.vis = true;
        return ret;
    }
    
    
    LL work(LL num) {
        for(int i = 0;i < maxn;i++) {
            for(int j = 0;j < 10;j++) {
                for(int k = 0;k < 10;k++) {
                    f[i][j][k] = EE();
                }
            }
        }
        getlim(num);
        EE ret = dfs(len,0,0,1,0);
        return ret.sqsum;
    }
    
    
    int main() {
        for(int i = 1;i < maxn;i++) p10[i] = p10[i - 1] * 10;
        int T; cin >> T;
        LL n,m;
        while(T--) {
            cin >> n >> m;
            cout << (work(m) - work(n - 1) + MOD) % MOD << endl;
        }
        return 0;
    }
    

      

  • 相关阅读:
    oracle 自增序列实现 可作为主键
    oracle 10 升级补丁
    软件设计原则
    oracle查询截至到当前日期月份所在年份的所有月份
    Dockerfile 基本命令
    Mybatis自动生成代码,MyBatis Generator
    Java垃圾回收机制
    SqlServer 导入 .sql 文件
    备份个清库脚本
    备份一些开发配置
  • 原文地址:https://www.cnblogs.com/rolight/p/3888361.html
Copyright © 2020-2023  润新知