Balanced Numbers(好久没有1A了,激动死了)

看不懂我写的哪个字了,哪句话了,哪段代码了,欢迎提出来啦,大家一起学习一起进步啦
欢迎下方留言区交流

耐心读完你应该会懂得

题目,先认真读懂题了,下面有题意的解析

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

题目解析,这是不是一个B数

如果一个数是平衡数(b数),那么组成他的数字,如果是偶数,就应该含有奇数个,如果是奇数,就应该含有偶数个,比如 题目样例中的1 ~9 有四个,应该是2,4,6,8这四个,他们是偶数,只有一个(奇数个)偶数,所以是,3322不是b数,因为3322含有2个2,偶数应该含有奇数个才行,
333211也不是,3是奇数,却含有奇数个,所以不是

做题思路(数位dp+状压)

我们要确定他是不是b数,所以必须知道他每一位由什么组成,比如说含有几个1,含有几个2,几个3,但是呢我们又没有必要知道他到底含有几个,只需要知道含有的2是奇数还是偶数个
有几个问题

  1. 我们需要知道哪几个数的状态?
    其实就是9个数的状态,分别是0,1,2,3,4,5,6,7,8,9,我们需要知道一个数还有几个0,几个1,几个2

  2. 状态有几种?
    其实我们没有必要知道具体含有几个1,含有几个2,只需要知道含有的个数是偶数还是奇数
    但不是只有两种状态,因为对于33222来说,只含有3 与 2, 假如说把状态1定为含某个数偶数个,状态0为含有某个数奇数个,但是一开始的状态都是什么呢,对于322来说,那不含有的数字7,8,9,1,4,等状态都为0吗?,但是0表示含有奇数个啊,数字1的状态为0表示他含有奇数个,在最后判断时我们就把他判为不是b数,但是他其实是b数,他不含有1,含有偶数个3,奇数个2,所以我们需要三个状态
    这三个状态:0表示不含有某个数,1表示含有奇数个某个数,2表示含有偶数个某个数
    看下面这张图吧,应该会明白
    写的字不是很丑吧
    然后懂了这个原理就好了,看看代码,再解释一下细节

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include<stdio.h>
#include<string.h> 
#include<limits.h>
#include<stdbool.h>
#include<vector>
#include<queue>
#include<map>
#define maxn  1505
using namespace std;
#define ll long long 
int w[50];//存的每一位
ll dp[21][60000];
int sf[10]={19683,6561,2187,729,243,81,27,9,3,1};//3的多少次方
int check(int m,int sum)
{
	for(int i=0;i<m;i++)
	{
		sum=sum/3;
	}
	return sum%3;
}
int check_2(int m)//判断是不是奇数含有偶数个,偶数含有奇数个
{
	while(m)//相当于先处理的是9含有的个数
	{
		if(m%3==1)//看看奇数是不是含有偶数个,等于1说明含有奇数个所以返回0
		{
			return 0;//
			break;
		}
		m=m/3;
		if(m%3==2)//看看偶数是不是含有奇数个
		{
			return 0;
			break;
		}
		m=m/3;
	}
	return 1;
}
ll dfs(int pos,bool limit,bool pre,int st)
{
	if(pos==-1)
	{
		
		return check_2(st);//已经算完最后一位了,开始判断
	}
	if(!limit&&dp[pos][st]!=-1)
	{
		return dp[pos][st];
	}
	int up=limit?w[pos]:9;
	ll ans=0; 
	for(int i=0;i<=up;i++)
	{
	     int p=check(9-i,st);//pos位现在为i,p表示我们目前已经含有几个i了,是奇数个还是偶数个,还是一个没有
		if(pre&&i==0)//pre是用来判断前导零的,pre为真表示前面一直为0
		{
		ans+=dfs(pos-1,limit&&w[pos]==i,1,0);
		}//之所以判断前导0,是因为60007,把前导零和数含有的有效零区分开
		
		//int p=check(9-i,st);
		 else if(p==0||p==1)//本来运行到pos位,p=0表示前面一个i也没有,现在遇到一个就应该含有奇数个了,所以下面的状态为st+sf[i],变为1,p=1表示含有奇数个i,又遇到一个应该变为2
		{
		ans+=dfs(pos-1,limit&&w[pos]==i,0,st+sf[i]);//st+sf[i]是把3进制的某一位进行改变的
		}//
		else{//表示p=2表示含有偶数个i了,再加一个应该是奇数个了,再减一个sf[i]
			ans+=dfs(pos-1,limit&&w[pos]==i,0, );
		}
	
		 
		
	 } 
	 if(!limit)
	 {
	 	dp[pos][st]=ans;
	 }
	 return ans;
}
ll solve(ll n)
{
	int len=0;
	while(n)
	{
		w[len++]=n%10;
		n=n/10;
	}

	return dfs(len-1,1,1,0);
}
int main()
{
	int t;
	ll l,r;
	int i,j;
	scanf("%d",&t);
	memset(dp,-1,sizeof(dp));
	for(i=0;i<t;i++)
	{
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",solve(r)-solve(l-1));
		//printf("%d\n",check(l,r));
		//printf("%d\n",check(l));
		
	}
	return 0;
 } 

认为重要的都注释了呀,还有不明白的可以评论中问了,再解释一下这句
int p=check(9-i,st);//pos位现在为i,p表示我们目前已经含有几个i了,是奇数个还是偶数个,还是一个没有
想要理解这句需要看看check函数,0123456789,(从右往左看)对于一个三进制来说你要找含有几个2,应该看他的第八位,第八位的数表示含有奇数个2,还是偶数个2,还是一个也没有。你要循环除以几次3才找到那一位,是不是(9-2)次,除以7次,此时再%3,就是这一位含有的数p。而st是表示状态的3进制数.
再解释一下这句 0 1 2 3 4 5 6 7 8 9
**st+sf[i] st-sf[i]**其实就是三进制数(0 0 1 2 0 0 0 0 0 0),大家猜一下这个状态表示的是一个甚么样的状态,表示含有奇数个2,偶数个3,那如果现在这一位数是3,那么就有奇数个3了,那状态变为甚么呢,就是 (0 0 1 1 0 0 0 0 0 0) 吧,怎么变,要变化的是三进制的第7位,要由2变为1所以说减去3的6次方就好了,也就是我的sf数组里面存的数,事先算了算3的多少次方

我只能把题解写成这样了,哈哈水平有限。大家一定好好想,我想了很久,这题想了一晚上,当时状态想用2进制表示,但是怎么也不行,搜题解只在题目中看到一个三进制就把浏览器关了,自己试着写,学ACM,算法不容易,就得想,分析,和同学 学长讨论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值