Balanced Numbers(数位+状压)

题意:求给定区间,一个数的数位上每个奇数出现偶数次,每个偶数出现奇数次,这样数的个数

分析:先考虑状态,但总是想不全,所以要把状态压缩一下,用三进制,0 该数不放  1 放了奇数次 2放了偶数次

dp[i][j] 长度为i 状态是j的数字个数,需要前导0判断,前导0不能计入偶数出现的次数。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <complex>
#include <cassert>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
#define lson l,m,rt<<1
#define pi acos(-1.0)
#define rson m+1,r,rt<<11
#define All 1,N,1
#define read freopen("in.txt", "r", stdin)
const ll  INFll = 0x3f3f3f3f3f3f3f3fLL;
const int INF= 0x7ffffff;
const int mod =  1000000007;
ll dp[25][100000],a,b;
int bit[25],cas[15];
//化三进制
void get(int x) { for(int i=0; i<10; ++i) { cas[i]=x%3; x/=3; } }
//状态改变
int change(int x,int b) { get(x); if(cas[b]==0) cas[b]=1; else if(cas[b]==1) cas[b]=2; else cas[b]=1; int s=0,tmp=1; for(int i=0; i<10; ++i) { s+=cas[i]*tmp; tmp*=3; } return s; }
//判断符合条件
int judge(int s) { get(s); for(int i=0; i<10; ++i) { if(i%2&&cas[i]==1)return 0; if(i%2==0&&cas[i]==2)return 0; } return 1; } ll dfs(int i,int j,int f,int e) { if(i==0)return judge(j); if(!e&&dp[i][j]!=-1)return dp[i][j]; int u=e?bit[i]:9; ll num=0; for(int v=0; v<=u; ++v) { if(f&&v==0) num+=dfs(i-1,0,1,e&&(v==u)); else { num+=dfs(i-1,change(j,v),0,e&&(v==u)); } } if(!e)dp[i][j]=num; return num; } ll solve(ll x) { int len=0; while(x) { bit[++len]=x%10; x/=10; } return dfs(len,0,1,1); } int main() { int t; scanf("%d",&t); memset(dp,-1,sizeof(dp)); while(t--) { scanf("%I64d%I64d",&a,&b); printf("%I64d\n",solve(b)-solve(a-1)); } return 0; }

 

posted on 2015-07-27 18:22  积跬步、至千里  阅读(129)  评论(0编辑  收藏  举报

导航