SPOJ NUMTSN NUMTSN - 369 Numbers(数位dp)

NUMTSN - 369 Numbers

no tags

7. 369 numbers

A number is said to be a 369 number if

  1. The count of 3s is equal to count of 6s and the count of 6s is equal to count of 9s.
  2. The count of 3s is at least 1.

For Example 12369, 383676989, 396 all are 369 numbers whereas 213, 342143, 111 are not.

Given A and B find how many 369 numbers are there in the interval [A, B]. Print the answer modulo 1000000007.

Input

The first line contains the number of test cases (T) followed by T lines each containing 2 integers A and B.

Output

For each test case output the number of 369 numbers between A and B inclusive.

Constraints

T<=100

1<=A<=B<=10^50

Sample Input

3

121 4325

432 4356

4234 4325667

Sample Output

60

58

207159

链接:http://www.spoj.com/problems/NUMTSN/en/

/*
题意:求一段区间3 6 9 数目相同(且最少为1)的数的数目,
思路:注意到数非常大,有10^50次幂,所以用字符串保存
     然后数位dp  dp[i][j][k][m]分别代表到第i位,3 6 9 的数目

*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>

#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)

#define bug printf("hihi\n")

#define eps 1e-8

typedef long long ll;

using namespace std;
#define N 55
#define mod  1000000007

ll dp[N][N][N][N]; //
int bit[N];

void change(char *a)  //处理对于字符串减一操作
{
    int i,j;
    int len=strlen(a);
    len--;
    while(len>=0)
    {
        a[len]--;
        if(a[len]>='0') break;
        a[len]='9';
        len--;
    }
    len=strlen(a);
    for(i=0;i<len-1;i++) if(a[i]>='1') break;
    int k=0;
    for(i;i<len;i++)
        a[k++]=a[i];
    a[k]='\0';
}

ll dfs(int pos,int le,int mid,int ri,bool bound)
{
    if(pos==0) return le==mid&&mid==ri&&le>=1 ? 1:0;
    if(!bound&&dp[pos][le][mid][ri]>=0) return dp[pos][le][mid][ri];
    int up=bound ? bit[pos]:9;
    ll ans=0;
    for(int i=0;i<=up;i++)
    {
        if(i==3)
          ans=(ans+dfs(pos-1,le+1,mid,ri,bound&&i==up))%mod;
        else
          if(i==6)
           ans=(ans+dfs(pos-1,le,mid+1,ri,bound&&i==up))%mod;
        else
            if(i==9)
             ans=(ans+dfs(pos-1,le,mid,ri+1,bound&&i==up))%mod;
        else
             ans=(ans+dfs(pos-1,le,mid,ri,bound&&i==up))%mod;
    }
    if(!bound) dp[pos][le][mid][ri]=ans;
    return ans;
}

ll solve(char *c)
{
   int i,j;
   int len=strlen(c);
   for(i=1;i<=len;i++)
    bit[i]=c[len-i]-'0';

   return dfs(len,0,0,0,true)%mod;
}

int main()
{
    int i,j,t;
    char a[N],b[N];
    memset(dp,-1,sizeof(dp));
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s%s",a,b);
        change(a);
        printf("%lld\n",(solve(b)-solve(a)+mod+mod)%mod);//必须+mod % mod 因为可能是负数
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-09-29 04:03:30

SPOJ NUMTSN NUMTSN - 369 Numbers(数位dp)的相关文章

cf55dBeautiful numbers数位dp

想到 最小公倍数 其余的就好搞了 ,可是没想到 #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <

Balanced Numbers数位dp

三进制搞下, 0  表示没出现过,  第i位为1 表示 i出现了奇数次,  2表示i 出现了偶数次. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #includ

[Codefoces 401D]Roman and Numbers 数位dp

http://codeforces.com/problemset/problem/401/D 题目大意:给定一个数字n,将n的每一位数字重新排列,求在这些排列数之中可以被n整除的方法数. 解题思路: 暴力超时-- 大多数人的写法是进行位压缩,不过那样的话需要2^18*100 的空间,效率比较低,重复状态数较多,处理起来也不方便,这一题是给出了512M的空间.但是如果空间再小一倍,前者的方法就无能为力了. 发现有一种对于数位dp来说比较好的状态压缩方式,直接根据数码x出现的次数进行状态压缩.比如说

uva 10712 - Count the Numbers(数位dp)

题目链接:uva 10712 - Count the Numbers 题目大意:给出n,a,b:问说在a到b之间有多少个n. 解题思路:数位dp,dp[i][j][x][y]表示第i位为j的时候,x是否前面是相等的,y是否已经出现过n.对于n=0的情况要特殊处理前导0,写的非常乱,搓死. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using na

poj 3340 Barbara Bennett&#39;s Wild Numbers(数位DP)

Barbara Bennett's Wild Numbers Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3153   Accepted: 1143 Description A wild number is a string containing digits and question marks (like 36?1?8). A number X matches a wild number W if they hav

CodeForces 55D Beautiful numbers 数位DP+数学

题意大概是,判断一个正整数区间内有多少个整数能被它自身的每一个非零的数字整除. 因为每一个位置上的整数集s = {0,1,2,3,4,5,6,7,8,9} lcm(s) = 2520 现在有一个整数t是由s中一个或者多个数字构成的,记为abcde,显然t = a*10^4+b*10^3+c*10^2+d*10^1+e 要使得t能被a,b,c,d,e整除,必然有t % lcm(a,b,c,d,e) = 0 因为a,b,c,d,e去重之后一定是s的一个子集,所以lcm(s)一定是lcm(a,b,c,

HDU 4722 Good Numbers (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4722 思路:数位dp,dp[i][j]表示到第i位,数字和%10为j,然后进行dp,注意完全匹配的情况是要+1,而其他情况是从0 到 9 都要考虑 代码: #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; int

SPOJ BALNUM Balanced Numbers(数位dp)

Balanced Numbers Time Limit:123MS     Memory Limit:1572864KB     64bit IO Format:%lld & %llu Submit Status Practice SPOJ BALNUM Description Balanced numbers have been used by mathematicians for centuries. A positive integer is considered a balanced n

Codeforces Beta Round #51---D. Beautiful numbers(数位dp, 巧妙)

Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with this and just count the quantity of beautiful num

CodeForces 55D Beautiful numbers(数位dp&amp;&amp;离散化)

题目链接:[kuangbin带你飞]专题十五 数位DP A - Beautiful numbers 题意 ps:第一道数位dp,题真好,虽然是参考大牛方法悟过才a,但仍收获不少. 求一个区间内的Beautiful numbers有多少个.Beautiful numbers指:一个数能整除所有组成它的非0数字. 例如15可以被1和5整除,所以15是Beautiful numbers. 思路 Beautiful numbers指:一个数能整除所有组成它的非0数字. 等同于 一个数能整除 所有组成它的