212 P1768橘猫(数位dp)

www.cnblogs.com/shaokele/


橘猫##

  Time Limit: 1 Sec
  Memory Limit: 512 MB

Description###

  NiroBC 有了一间小屋,真是太好了,终于可以养猫了。
  NiroBC 想养N 只猫,编号为1……N。
  NiroBC 希望,第i 只猫为橘猫,当且仅当在i 的十进制表示下(不含前导零),每个阿拉伯数字出现的次数都是偶数。
  NiroBC 想知道她会养多少只橘猫。
 

Input###

  一行一个正整数N,表示猫的数量。
 

Output###

  一行一个整数,表示橘猫的数量。
 

Sample Input###

  65
  
  2360596325
  

Sample Output###

  5
  
  7080461
  

题目地址:yyhs校内题库

题目大意: 题目已经很简洁了>_<

题解:

  数位dp裸题


AC代码

#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
int len;
int a[20];
ll n;
ll dp[20][10][1024][2][2];
int main(){
	scanf("%lld",&n);
	while(n){
		a[++len]=n%10;
		n/=10;
	}
	for(int i=1;i<=len/2;i++)
		swap(a[i],a[len-i+1]);
	//dp[i][j][k][p][q]
	//第i位,取j,状态为k,是否贴上界,是否有前导0 
	dp[1][0][0][0][1]=1;
	for(int i=1;i<a[1];i++)
		dp[1][i][1<<i][0][0]=1;
	dp[1][a[1]][1<<a[1]][1][0]=1;
	for(int i=1;i<len;i++){
		//有前导0  
		dp[i+1][0][0][0][1]+=dp[i][0][0][0][1];
		for(int p=1;p<=9;p++)
			dp[i+1][p][1<<p][0][0]+=dp[i][0][0][0][1];
		//没前导0 
		for(int j=0;j<=9;j++)
			for(int k=0;k<(1<<10);k++){
				for(int p=0;p<=9;p++)
					dp[i+1][p][k^(1<<p)][0][0]+=dp[i][j][k][0][0];
				for(int p=0;p<a[i+1];p++)
					dp[i+1][p][k^(1<<p)][0][0]+=dp[i][j][k][1][0];
			}
		//贴上界 
		for(int k=0;k<(1<<10);k++)
			dp[i+1][a[i+1]][k^(1<<a[i+1])][1][0]+=dp[i][a[i]][k][1][0];
	}
	ll ans=0;
	for(int i=0;i<=9;i++)
		for(int j=0;j<=1;j++)
			for(int k=0;k<=1;k++)
				ans+=dp[len][i][0][j][k];
	printf("%lld
",ans-dp[len][0][0][0][1]);
	return 0;
}
原文地址:https://www.cnblogs.com/shaokele/p/9361048.html