• HDU 4507 求指定范围内与7不沾边的所有数的平方和 (数位DP)


    题意:
    求区间[l,r]内所有与7无关的数的平方和(取模)
    定义与7无关的数: 
                                         1.数字的数位上不能有7
                                         2.数字的数位和不能是7的倍数
                                         3.数字本身不能是7的倍数
    分析:
    状态的保存:
    1.数位上不能有7: 只需枚举数位的数字的时候跳过7就好 if (i == 7) continue;
    2.数位和不能是7的倍数: 那么开一维保存数位和除以7的余数
    3.数字本身不能是7的倍数:再开一维保存数字除以7的余数
    综上,dp[i][j][k]3个维度保存的数字属性分别是:
                               i : 当前处理的数位
                               j : 数位和%7 等于j
                               k: 数字本身%7等于k
    对于具有上述属性的数,用dp保存它们的3个值:(用结构体)
                             cnt: 具有该属性的所有数字的个数
                             s :具有该属性的所有数字的和
                             ss:具有该属性的所有数字的平方和
    为什么要保存这3个值?为了下面的计算
    状态的转移:
    关于状态转移,先简单的写这样一个式子:dp[i][j][k] = ∑dp[i-1][(j+dig)%7][(k*10+dig)%7](这里的求和符号不指加法,是一个抽象的意义)

    其中dig是枚举的正在处理的数位i上所有可能的数字(这个式子只能帮助理解状态是如何转移的但是却不表示具体的运算,dp是结构体当然不能直接运算)

    上面的等式,我们称等式左边表示总状态,等式右边为其子状态,显然总状态是等于所有子状态的“总和”(我说的状态的总和并非指加法运算)

    那么怎么通过子状态算出总状态呢?

    具体的计算:

    先说几句废话:

    对于1234这个数,它的数位上的数是1,2,3,4,它的数位和是1+2+3+4,它自身的数值是 1*1000+2*100+3*10+4

    如果我知道数字234是与7无关的数,在其前面加一个1,也是与7无关的数,我是怎样计算在其前面加一个1之后的数的平方和的呢

    (1*1000)^2 + 2*(1*1000)*234 + 234^2  这里相当于(1000+234)^2

    注意:在具体的状态转移中,我们是不知道234这个值,我们只知道有这么一个子状态

    另外,这只是一个数的平方,我们要求的是所有满足的数的平方和,所以最后具体的算式如下:

    设总状态为ans,它其中一个子状态为tmp,枚举正在处理的这一数位上的数字为 i ,数位 i 在整个数字中具体的数值是i*10^p

    那么有: //这里自己手算写写就会懂了,注意这里都是+=,都是加上这位数后面的个数跟状态。

                     (1) ans.cnt += tmp.cnt

                     (2) ans.s += tmp.s + [ i*10^p ]*tmp.cnt    //之所以*数量,是因为后面有许多个符合条件的数,这一位可以跟后面所有符合条件的数搭配    

                     (3) ans.ss += tmp.ss + 2*(i*10^p)*tmp.s + [(i*10^p)^2]*tmp.cnt //这里的中间部分两倍那里,比较坑。。。

    之所以变态是因为这个数太大了,不懂不懂就爆long long 所以哪里都要%Mod,少一个Mod就wa,另外这题比较新,返回的是结构体,判断记忆化的时候,也是用结构体里的变量实现的,通过构造函数初始化

    总结题目是个好习惯: 完全没有想到原来是可以用结构体dfs    , 而且考虑的也不全面 ,虽然之前的打法粗糙的想法是过了案例 , 但仔细想想又不行 , 还是太年轻了

    /*
     *  如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
      1、整数中某一位是7;
      2、整数的每一位加起来的和是7的整数倍;
      3、这个整数是7的整数倍;
    
    求一个区间中与7无关的数的平方和
     */
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    const long long MOD=1000000007LL;
    struct Node
    {
        long long cnt;//与7无关的数的个数
        long long sum;//与7无关的数的和
        long long sqsum;//平方和
    }dp[20][10][10];//分别是处理的数位、数字和%7,数%7
    int bit[20];
    long long p[20];//p[i]=10^i
    
    Node dfs(int pos,int pre1,int pre2,bool flag)
    {
        if(pos==-1)
        {
            Node tmp;
            tmp.cnt=(pre1!=0 && pre2!=0);
            tmp.sum=tmp.sqsum=0;
            return tmp;
        }
        if(!flag && dp[pos][pre1][pre2].cnt!=-1)
            return dp[pos][pre1][pre2];
        int end=flag?bit[pos]:9;
        Node ans;
        Node tmp;
        ans.cnt=ans.sqsum=ans.sum=0;
        for(int i=0;i<=end;i++)
        {
            if(i==7)continue;
            tmp=dfs(pos-1,(pre1+i)%7,(pre2*10+i)%7,flag&&i==end);
            ans.cnt+=tmp.cnt;
            ans.cnt%=MOD;
            ans.sum+=(tmp.sum+ ((p[pos]*i)%MOD)*tmp.cnt%MOD )%MOD;
            ans.sum%=MOD;
    
            ans.sqsum+=(tmp.sqsum + ( (2*p[pos]*i)%MOD )*tmp.sum)%MOD;
            ans.sqsum%=MOD;
            ans.sqsum+=( (tmp.cnt*p[pos])%MOD*p[pos]%MOD*i*i%MOD );
            ans.sqsum%=MOD;
        }
        if(!flag)dp[pos][pre1][pre2]=ans;
        return ans;
    }
    long long calc(long long n)
    {
        int pos=0;
        while(n)
        {
            bit[pos++]=n%10;
            n/=10;
        }
        return dfs(pos-1,0,0,1).sqsum;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int T;
        long long l,r;
        p[0]=1;
        for(int i=1;i<20;i++)
            p[i]=(p[i-1]*10)%MOD;
        for(int i=0;i<20;i++)
            for(int j=0;j<10;j++)
                for(int k=0;k<10;k++)
                    dp[i][j][k].cnt=-1;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%I64d%I64d",&l,&r);
            long long ans=calc(r);
            ans-=calc(l-1);
            ans=(ans%MOD+MOD)%MOD;
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Django实战—权限管理系统rbac组件实现
    Django模型层的DateTimeField、DateField字段设置时间格式为显示当前年月日时分秒的时间格式及时区
    mysql数据库删除一条数据之后,主键id不连续的问题解决
    python多继承(super().__init__())、*args和**kwargs、
    Django数据库操作中You are trying to add a non-nullable field 'name' to contact without a default错误处理
    配置等模版
    【SSM】(一)SSM整合-增删改查书籍
    【SpringMVC】(八)使用Ajax前后端传数据&不使用Ajax
    【SpringMVC】@RequestMapping注意点
    leetcode (堆->中级) 264,313,347,373,378,767,1642,973,1673,743,787
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9926629.html
Copyright © 2020-2023  润新知