SPOJ BALNUM Balanced Numbers(数位dp,状态压缩)

BALNUM - Balanced Numbers

no tags

题目链接

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

题意是给出一个范围,求出这个范围中的平衡数的数量,平衡数是指这个数各个位置中的每种偶数都出现了奇数次,每种奇数都出现了偶数次。(也都可以不出现)做法是用两个数t1, t2保存两种状态,t1保存(0~9)中的各个数字是否出现过,t2保存(0~9)中的各个偶数是否出现了奇数次,奇数是否出现了偶数次(先预处理)。这样子的话用(t1 & t2 == 0) 可以判断总的状态是否符合条件。显然t1、t2等于2 ^ 10 = 1024。并且注意这道题里翻转过来的数字的第一位是0的话也会影响答案,所以如果高位为0时向下传递初始的状态。我用zip表示了压缩的初始的状态,毕竟zip是压缩包嘛_(:з」∠)_,然后就是简单的搞数位dp了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <bitset>
using namespace std;
#define ll long long
ll n, m;
ll dp[20][1024][1024];
int dig[20];
int zip;

void init() {
    for(int i = 0; i < 10; i += 2) zip ^= (1 << i);
    memset(dp, -1, sizeof(dp));
    /*bitset<10> btt(zip);
    cout << btt << endl;*/
}

void print(int num) {
    bitset<10> btt(num);
    cout << btt << endl;
}

ll dfs(int pos, int t1, int t2, int flag0, int lim) {
    //print(t1); print(t2); puts("");
    if(pos == -1) return (t1 & t2) == 0;
    if(!lim && dp[pos][t1][t2] != -1) return dp[pos][t1][t2];
    int End = lim ? dig[pos] : 9;
    ll ret = 0;
    for(int i = 0; i <= End; i++) {
        if(i == 0 && flag0) ret += dfs(pos - 1, 0, zip, 1, (i == End) && lim);
        else ret += dfs(pos - 1, t1 | (1 << i), t2 ^ (1 << i), 0, (i == End) && lim);
    }
    if(!lim) dp[pos][t1][t2] = ret;
    return ret;
}

ll func(ll num) {
    int n = 0;
    while(num) {
        dig[n++] = num % 10;
        num /= 10;
    }
    return dfs(n - 1, 0, zip, 1, 1);
}

int main() {
    init();
    int t;
    scanf("%d", &t);
    while(t--) {
        scanf("%I64d %I64d", &n, &m);
        printf("%I64d\n", func(m) - func(n - 1));
    }
}
 
				
时间: 2024-10-04 23:58:49

SPOJ BALNUM Balanced Numbers(数位dp,状态压缩)的相关文章

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

SPOJ10606 BALNUM - Balanced Numbers(数位DP+状压)

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 numb

spoj 10606 Balanced Numbers 数位dp

题目链接 一个数称为平衡数, 满足他各个数位里面的数, 奇数出现偶数次, 偶数出现奇数次, 求一个范围内的平衡数个数. 用三进制压缩, 一个数没有出现用0表示, 出现奇数次用1表示, 出现偶数次用2表示, 这样只需要开一个20*60000的数组. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pb(x) push_back(x) 4 #define ll long long 5 #define mk(x, y) make_

Codeforce 401D Roman and Numbers[数位DP+状态压缩]

给出数n和m,求n的所有排列中,模m得0的有多少个 n (1?≤?n?<?1018) and m (1?≤?m?≤?100). 暴力法我们直接枚举n的所有排列,显然18!超时. 考虑怎么dp 假设给了我们数n=23765 显然有 (237%m*10+6)%m=2376%m (367%m*10+2)%m=3672 我们很自然的想到了 这样的状态转移 dp[i][k] i代表取的数的状态 代表在取数状态为i的情况下模m为k的数有多少 比如 对于23765的356 取数状态为01011 dp方程就是

SPOJ BALNUM Balanced Numbers 状压+数位DP

一开始想了一个用二进制状压的方法,发现空间需要的太大,光光memset都要超时 = = 其实不用每次都memset 也可以用三进制,一开始直接打表出所有的状态转移就好 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream&g

hdu 4352 数位dp + 状态压缩

XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2265    Accepted Submission(s): 927 Problem Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then careful

【HDU 4352】 XHXJ&#39;s LIS (数位DP+状态压缩+LIS)

XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2422    Accepted Submission(s): 990 Problem Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then careful

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

[数位dp+状态压缩] hdu 4352 XHXJ&#39;s LIS

题意: 给x.y.k,在[x,y] 范围内最长上升子序列长度是k的数有几个 思路: 模仿 LIS nlogn的想法,这里就只有10个数,进行状压 然后直接搜就好了不用二分 然后按位dp下去就ok了! 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"al