hdu4507(数位DP)

题目意思: 给定一个区间,求这段区间中,不含7,对7取余为0,各个位数相加之和对7取余为0的数的平方和。

设d[i][j][k][m]代表长度为i的,对7取余为j的,各个位数相加之和对7取余为k的数的平方和,

但是算平方和需要用到这些数的和,这些数的个数。所以用了一个结构体数组保存每种状态的Count,sum1,.sum2;

(ago+k1)^2+(ago+k2)^2+(ago+k3)^2=3*ago^2+2*ago*(k1+k2+k3)+k2^2+k2^2+k3^2;

=Count1*ago^2+2*ago*sum1+sum2;

需要注意取模运算和long long

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define MOD 1000000007
#define maxn 20
using namespace std;
const int N=20;
LL  md[N];
LL  digit[maxn];
LL ans=0;
struct node
{
   LL Count=0,sum1=0,sum2=0;
};
node dp[maxn][7][7][2];
int visit[maxn][7][7][2];
node  dfs(int len,int pre,int before, int state,bool fp) //dfs版本的纯属暴力枚举每一个数字,而递推版本的是考虑了前缀的影响
{
    if(state)
         {
             node temp;
             temp.Count=0;
             temp.sum1=0;
             temp.sum2=0;
             return temp;
         }
    if(len==0 && (pre==0 || before==0))
        {
             node  temp;
             temp.Count=0;
             temp.sum1=0;
             temp.sum2=0;
             return temp;
        }
    else if(len==0)
        {
              node  temp;
             temp.Count=1;
             temp.sum1=0;
             temp.sum2=0;
             return temp;
        }
    if(!fp && visit[len][pre][before][state]== 1) //
    {
         return dp[len][pre][before][state];
    }
    node  ret ;
    int  fpmax = fp ? digit[len] : 9 ;
    for(int i=0;i<=fpmax;i++) //分别算出以i开头的数的方案数,
    {
        node next=dfs(len-1,(((pre*10+i))%7) ,(before+i)%7,i==7 | state,fp && i == fpmax);
        //temp=temp%MOD;
        //ret+=(temp*temp)%MOD;
        LL  ago   = ( i*md[len-1] )%MOD;
        ret.Count = (ret.Count +  next.Count) %MOD;
        ret.sum1  = (ret.sum1  + ( ago*next.Count ) %MOD + next.sum1) %MOD;
        ret.sum2  = ( ret.sum2 + (next.Count* ( (ago*ago )%MOD ) ) %MOD +(2*ago*next.sum1)%MOD + next.sum2 ) %MOD;
    }
    if(!fp)
    {
        dp[len][pre][before][state]= ret;
        visit[len][pre][before][state]=1;
    }
    return  ret;
}

LL f(LL n)
{
    int len=0;
    while(n)
    {
        digit[++len] = n % 10;
        n /= 10;
    }
    LL ans=0;
    ans+=dfs(len,0,0,0,true).sum2;
     return ans;
}
void init()
{
    memset(visit,0,sizeof(visit));
}
int main()
{
   // freopen("test.txt","r",stdin);
    int t;
    scanf("%d",&t);
    md[0]=1;
    for(int i=1;i<=N;i++)
        md[i]=(md[i-1]*10)%MOD;
    while(t--)
    {
        init();
        LL n,m;
        scanf("%I64d%I64d",&n,&m);
         LL ans1=f(m);
         LL ans2=f(n-1);
       printf("%I64d\n", (ans1-ans2 + MOD)%MOD );
    }
    return 0;
}
时间: 2024-10-21 10:25:15

hdu4507(数位DP)的相关文章

【HDU4507】恨7不成妻(数位DP)

点此看题面 大致题意: 让你求出一段区间内与\(7\)无关的数的平方和.与\(7\)无关的数指整数中任意一位不为\(7\).整数的每一位加起来的和不是\(7\)的整数倍.这个整数不是\(7\)的倍数. 数位\(DP\) 这题应该比较显然是一道 数位\(DP\) 题. 如何记录状态 这道题关键就在于如何记录状态,其余的就和普通的数位\(DP\)差不多了. 我们可以用\(f_{x,s1,s2}\)来表示还剩\(x\)位,这个数除末\(x\)位以外模\(7\)余\(s1\),这个数每一位之和除末\(x

hdu-4507 吉哥系列故事——恨7不成妻 数位DP 状态转移分析/极限取模

http://acm.hdu.edu.cn/showproblem.php?pid=4507 求[L,R]中不满足任意条件的数的平方和mod 1e9+7. 条件: 1.整数中某一位是7:2.整数的每一位加起来的和是7的整数倍:3.这个整数是7的整数倍: 首先想到数位DP,我们看下如何维护. 最基本的dp需要两维来维护起始数字和长度,此外对于数位求和mod 7的余数需要一维来维护,对于一个数mod 7的余数需要一维维护. 此外我们处理一下平方和,对于一个x开头,长度为len的xoo型数集,把它分成

HDU4507 吉哥系列故事——恨7不成妻 题解 数位DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4507 题目大意: 找到区间 \([L,R]\) 范围内所有满足如下条件的数的 平方和 : 不包含'7': 不能被 7 整除: 各位之和不能被 7 整除. 注意:求的是满足条件的数的 平方和 ! 解题思路: 使用 数位DP 尽情求解. 但是因为这里求的是满足要求的元素的平方和,而不是元素的个数. 所以我们不能简单地开long long来存放结果, 而是开一个结构体来存放结果,结构体中需要包含三个元素:

数位dp专题 (HDU 4352 3652 3709 4507 CodeForces 55D POJ 3252)

数位dp核心在于状态描述,因为阶段很简单. 一般都是求有多少个数,当然也有求平方的变态题. 因为比这个数小的范围定然是从左至右开始小的,那么什么样的前缀对后面子数有相同的结果? HDU 3652 题意:求能被13整除且含有13这样数的个数. 赤裸裸的两个条件,加上个pre标明下前缀,其实直接开状态也是一样的.整除这个条件可以用余数来表示.余数转移:(mod*10+i)%13 /* *********************************************** Author :bi

数位dp小记

转载自:http://blog.csdn.net/guognib/article/details/25472879 参考: http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html kuangbin :http://www.cnblogs.com/kuangbin/category/476047.html http://blog.csdn.net/cmonkey_cfj/article/details/7798809 http:/

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是

51nod1043(数位dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1043 题意:中文题诶- 思路:数位dp 我们用dp[i][j]来存储长度为2*i且一半和为j的所有情况(包括前导0的情况),为了方便我们现在只讨论其一半的和的情况,因为如果包括前导0的话其两边的情况是一样的: 我们假设再长度为i-1的数字最前面加1位数字k,0<=k<=9(这位数字加在哪里并不影响答案,因为我们在计算i-1长度的时候已经计算了所有组合情况,

数位dp

1.[hdu3709]Balanced Number 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<ctime> 8 #include<cmath> 9 #include<queue>