【HDU】3943 K-th Nya Number 数位DP

传送门:【HDU】3943 K-th Nya Number


题目分析:数位DP预处理出每一个状态下数的个数,然后每次询问就递推一下。dp数组记录了之前是从哪个数字过来时可以比较方便的处理本题。这题代码应该是被我写复杂了= =。


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
  
typedef long long LL ;
 
#pragma comment(linker, "/STACK:16777216")

#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )
#define now cur][j][flag][four][seven

LL dp[20][10][2][21][21] ;
int vis[20][10][2][21][21] , Time ;
LL ten[20] ;
int digit[20] , n1 ;
int x , y ;
LL kth , ans , sum ;

LL dfs ( int cur , int j , int flag , int four , int seven ) {
	if ( vis[now] == Time ) return dp[now] ;
	vis[now] = Time ;
	if ( !cur ) return dp[now] = ( four == x && seven == y ) ;
	LL& ans = dp[now] = 0 ;
	if ( flag ) {
		rep ( i , 0 , 10 ) ans += dfs ( cur - 1 , i , 1 , four + ( i == 4 ) , seven + ( i == 7 ) ) ;
	} else {
		rep ( i , 0 , digit[cur] ) ans += dfs ( cur - 1 , i , 1 , four + ( i == 4 ) , seven + ( i == 7 ) ) ;
		ans += dfs ( cur - 1 , digit[cur] , 0 , four + ( digit[cur] == 4 ) , seven + ( digit[cur] == 7 ) ) ;
	}
	return ans ;
}

LL deal ( LL n ) {
	n1 = 0 ;
	while ( n ) {
		digit[++ n1] = n % 10 ;
		n /= 10 ;
	}
	++ Time ;
	LL ans = dfs ( n1 , 0 , 0 , 0 , 0 ) ;
	return ans ;
}

void dfs2 ( int cur , int j , int flag , int four , int seven ) {
	if ( !cur ) return ;
	int i ;
	if ( flag ) {
		for ( i = 0 ; i < 10 ; ++ i ) {
			LL tmp = sum + dp[cur - 1][i][1][four + ( i == 4 )][seven + ( i == 7 )] ;
			if ( tmp < kth ) sum = tmp ;
			else break ;
			if ( i == 9 ) break ;
		}
		ans += i * ten[cur - 1] ;
		dfs2 ( cur - 1 , i , 1 , four + ( i == 4 ) , seven + ( i == 7 ) ) ;
	} else {
		for ( i = 0 ; i <= digit[cur] ; ++ i ) {
			LL tmp = sum + dp[cur - 1][i][i != digit[cur]][four + ( i == 4 )][seven + ( i == 7 )] ;
			if ( tmp < kth ) sum = tmp ;
			else break ;
			if ( i == digit[cur] ) break ;
			sum = tmp ;
		}
		ans += i * ten[cur - 1] ;
		dfs2 ( cur - 1 , i , i != digit[cur] , four + ( i == 4 ) , seven + ( i == 7 ) ) ;
	}
}

void solve () {
	int n ;
	LL P , Q ;
	scanf ( "%I64d%I64d%d%d" , &P , &Q , &x , &y ) ;
	LL cnt1 = deal ( P ) ;
	LL cnt2 = deal ( Q ) ;
	scanf ( "%d" , &n ) ;
	while ( n -- ) {
		scanf ( "%I64d" , &kth ) ;
		kth += cnt1 ;
		if ( cnt2 < kth ) {
			printf ( "Nya!\n" ) ;
			continue ;
		}
		sum = ans = 0 ;
		dfs2 ( n1 , 0 , 0 , 0 , 0 ) ;
		printf ( "%I64d\n" , ans ) ;
	}
}

int main () {
	int T , cas = 0 ;
	clr ( vis , 0 ) ;
	Time = 0 ;
	ten[0] = 1 ;
	rep ( i , 1 , 20 ) ten[i] = ten[i - 1] * 10 ;
	scanf ( "%d" , &T ) ;
	while ( T -- ) {
		printf ( "Case #%d:\n" , ++ cas ) ;
		solve () ;
	}
	return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值