spoj10606 数位dp (求出现的数字,所有偶数出现奇数次,所有奇数出现偶数次)

http://www.spoj.com/problems/BALNUM/

SPOJ Problem Set (classical)

10606. Balanced Numbers

Problem code: BALNUM

Balanced numbers have been used by mathematicians for centuries. A positive integer is considered a balanced number if:

1)      Every even digit appears an odd number of times in its decimal representation

2)      Every odd digit appears an even number of times in its decimal representation

For example, 77, 211, 6222 and 112334445555677 are balanced numbers while 351, 21, and 662 are not.

Given an interval [A, B], your task is to find the amount of balanced numbers in [A, B] where both A and B are included.

Input

The first line contains an integer T representing the number of test cases.

A test case consists of two numbers A and B separated by a single space representing the interval. You may assume that 1 <= A <= B <= 1019

Output

For each test case, you need to write a number in a single line: the amount of balanced numbers in the corresponding interval

Example

Input:
2
1 1000
1 9
Output:
147
4

/**
spoj10606 数位dp (求出现的数字,所有偶数出现奇数次,所有奇数出现偶数次)
解题思路:3进制表示数字0~9的出现情况,0表示没有出现,1表示奇数次,2表示偶数次
*/
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
LL dp[20][60000];
int bit[20];
bool check(int s)
{
    int num[10];
    for(int i=0;i<10;i++)
    {
        num[i]=s%3;
        s/=3;
    }
    for(int i=0;i<10;i++)
    {
        if(num[i]!=0)
        {
            if(i%2==0&&num[i]==2)return false;
            if(i%2==1&&num[i]==1)return false;
        }
    }
    return true;
}
int getnews(int x,int s)
{
    int num[10];
    for(int i=0;i<10;i++)
    {
        num[i]=s%3;
        s/=3;
    }
    if(num[x]==0)
        num[x]=1;
    else
        num[x]=3-num[x];
    int news=0;
    for(int i=9;i>=0;i--)
    {
        news*=3;
        news+=num[i];
    }
    return news;
}

LL dfs(int pos,int s,int flag,int z)
{
    if(pos==-1)return check(s);
    if(!flag&&dp[pos][s]!=-1)
        return dp[pos][s];
    LL ans=0;
    int end=flag?bit[pos]:9;
    for(int i=0;i<=end;i++)
    {
        ans+=dfs(pos-1,(z&&i==0)?0:getnews(i,s),flag&&i==end,z&&i==0);
    }
    if(!flag)dp[pos][s]=ans;
    return ans;
}
LL solve(LL n)
{
    int len=0;
    while(n)
    {
        bit[len++]=n%10;
        n/=10;
    }
    return dfs(len-1,0,1,1);
}

int main()
{
    int T;
    memset(dp,-1,sizeof(dp));
    LL a,b;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&a,&b);
        printf("%lld\n",solve(b)-solve(a-1));
    }
    return 0;
}
时间: 2024-08-22 03:15:19

spoj10606 数位dp (求出现的数字,所有偶数出现奇数次,所有奇数出现偶数次)的相关文章

(数位DP)51NOD 1042 数字0-9的数量

给出一段区间a-b,统计这个区间内0-9出现的次数. 比如 10-19,1出现11次(10,11,12,13,14,15,16,17,18,19,其中11包括2个1),其余数字各出现1次. 输入 两个数a,b(1 <= a <= b <= 10^18) 输出 输出共10行,分别是0-9出现的次数 输入样例 10 19 输出样例 1 11 1 1 1 1 1 1 1 1 解:被这道题卡了好久...最后自己找了个数模拟了一边流程.举个例子简单说说:对于数5314,我们可以将它拆分为[5310

ac1068 数位dp

这题说的是给了一个区间计算这个区间内 数各个数字之和为S的最小数 其实这个题目首先可以求出[A,B]内所有数字之和为S的数的个数cnt,然后观察一下,不难发现,最小的那个数字肯定是在 cnt=1的时候对应的区间端点.由于具有严格的单调性,即随着区间长度的延长,满足条件的cnt肯定会越来越多.所以先可以数位dp求出cnt.然后二 分区间,若cnt>=1,那么说明[A,B]间肯定不止一个符合条件的数字.注意题目要求最小的数字,所以二分区间右端点即可,不要二分左端.这是 主要思路.其实就是个裸的数位d

2017年icpc西安网络赛 Maximum Flow (找规律+数位dp)

题目 https://nanti.jisuanke.com/t/17118 题意 有n个点0,1,2...n-1,对于一个点对(i,j)满足i<j,那么连一条边,边权为i xor j,求0到n-1的最大流,结果取模,n<=1e18 分析 可以写个最大流对数据找规律,但没找出来…… 然后只能取分析了,首先最大流等价于最小割 明确一定,0->n-1这个要先割掉 然后我们贪心,希望有一些点割掉与0相连的边,一些点割掉与n-1相连的边 我们去观察每个点与0相连和与n-1相连的两条边权值,容易发现

SHUOJ 1771 - 奇偶和(数位DP)

http://202.121.199.212/JudgeOnline/problem.php?id=1771 夏季赛H题 Description Input 第一行含有一个正整数 T,表示有 T 组测试数据. 每组数据只有一行,包含三个整数 L_i,R_i,m. 约定     T≤200:     0≤L≤R≤10^18:     |m|≤100. Output 对于每组测试用例,输出: 第一行:Case #: (# 要替换成对应的数字). 输出两个整数,用一个空格分割.分别为在 [L_i,R_

POJ 3286 How many 0&#39;s(数位DP模板)

题目链接:http://poj.org/problem?id=3286 题目大意: 输入n,m,求[n,m]的所有数字中,0出现的总数是多少,前导零不算. 解题思路: 模板题,设dp[pos][num],pos为数位,num为当前0的数目,然后套数位DP模板即可. 还有之前的一些思考: 关于数位DP求0时,dp下标记录num有什么作用,num不是与后面的0的个数无关吗?是的,在(!limit&&!lead)的情况下,前面有多少0是不影响后面可以出现多少0的.但是,比如说dp[pos][nu

【SCOI2014】【BZOJ3598】方伯伯的商场之旅(数位dp)

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3598 题意: 对于一个数x,它含有一些小石子,每个石子的值为a[i](a[i]为x在k进制下的第i位),选一个石子的位置pos使得sum(a[i] * abs(i-pos))最小. 求出[L,R]中所有数这个值的和. 题解: 对于一个数,我们枚举最优位置时,可以发现从i->i+1的变化为+pre[i]-suf[i+1](分别为前缀和与后缀和). 30%的暴力分,我们枚举[L,R]中的数,然

[数位dp] kuangbinoj 1012 bin巨的数

题意: 作为ACM史上年度重量级人物,bin巨目前已经掌握了史上最NB的数,群巨快来仰慕!!我们定义这样一个数,它里面的每一个数字都是成双成对出现 的,but,如果这个数里面存在0那么这也是NB的数,比如11,122122,12035,当然,需要剔除那些首位是0的数.我们的目标就是计算一个区 间内bin巨有多少NB数! 思路: 简单的数位dp,需要考虑每个数字出现的次数(0,1),是否有前导0,是否出现了0. 这里需要注意的就是0不是一个bin巨数. #include"cstdlib"

Codeforces 1245F. Daniel and Spring Cleaning(容斥原理+数位DP)

传送门 题目大意 给你两个数,\(l,r\) 求 \([l,r]\) 中多少对 \(a+b=a\oplus b\). 思路 看了大佬的题解才知道这里要用到二维容斥. 设 \(f_{x,y}\) 是 \(a\in [0,x],b\in [0,y]\) 时满足条件的对数 那么根据容斥原理答案就是 \(f_{r,r}-f_{l-1,r}\times 2+f_{l-1,l-1}\) 对于其中每一部分都可以用一次数位DP求出来 因为这里对于统计有影响的因素只有两个数是否被限制 那么状态可以直接设计为 \(

HDU3555 Bomb 题解 数位DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:求 \([1,n]\) 范围内有多少数包含"49". 解题思路: 这个问题我们可以分两种解法来考虑:第一种是求不包含"49"的数的数量,用后减一下:另一种就是直接求包含"49"的数的数量. 解法1:求多少数不包含"49" 这种方法我们先通过数位DP求出 \([0,n]\) 区间范围内有多少数不包含"49&