uvalive 4031 - Integer Transmission

这道题。。最开始看的时候不知道怎么做。。经过将讲解。。开始理解了。。数位dp状态定义大概是这样子的。。 f[i][j][k] (其实可以省略一维,不过空间足够,写起来更方便)第i个位置,用到第j个0,第i个1了。呃。。我听了状态的定义还是不太明白。。然后做法是这个样子的:从二进制低位到高位依次填数字(0或1),当然,填数字是有限制的。。。考虑原数字k的二进制形势,举个例子:当1
摘要由CSDN通过智能技术生成

这道题。。最开始看的时候不知道怎么做。。经过将讲解。。开始理解了。。

数位dp

状态定义大概是这样子的。。 f[i][j][k] (其实可以省略一维,不过空间足够,写起来更方便)第i个位置,用到第j个0,第i个1了。

呃。。我听了状态的定义还是不太明白。。

然后做法是这个样子的:从二进制低位到高位依次填数字(0或1),当然,填数字是有限制的。。。

考虑原数字k的二进制形势,举个例子:当11101(2)=k , d=2 的时候 最左边的1是不能够移到0的右边的,而第二个1就可以,那么构成的新的数字就是11011(2),可以看成是把1弄到了0的右边。。。也就是说,当 当前的1的位置+d > 当前0的位置 的时候 能够将1移动到0的右边,就能够构成新的数字了嘛 = =。。

另外两个问题就不讨论了。。

下面是代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL unsigned long long
using namespace std ;
LL num0 , num1 , n , d , k , T;
bool vis[200][100][100] ;
LL f[200][100][100] ;
int s0[200] , s1[200] ;

LL dfs(int p,int p0,int p1) {
	//if(p == n && p0 == num0 && p1 == num1) return 1 ;
	LL &x = f[p][p0][p1] ;
	if(vis[p][p0][p1]) return x ;
	vis[p][p0][p1] = true ; 
	x = 0 ; bool op = true ;
	if(p0 < num0 && p1 < num1) {
		if(s0[p0] + d < s1[p1]) x = dfs(p+1 , p0+1 , p1) , op = false ;
		else if(s1[p1] + d < s0[p0]) x = dfs(p+1 , p0 , p1+1) , op = false ;
	}
	if(op) {
		if(p0 < num0) x = dfs(p+1 , p0+1 , p1) ;
		if(p1 < num1) x += dfs(p+1 , p0 , p1+1) ;
	}
	return x ;
}

int main() {
	while(~scanf("%llu",&n)) {
		if(!n) break ;
		scanf("%llu%llu",&d,&k) ;
		num0 = num1 = 0 ;
		for(int i = 0 ; i < n ; i++) {
			if(k&1) s1[num1++] = i ;
			else s0[num0++] = i ;
			k >>= 1 ;
		}
		memset(vis , 0 , sizeof(vis)) ;
		memset(vis[n] , 1 , sizeof(vis[n])) ;
		memset(f[n] , 0 , sizeof(f[n])) ;
		f[n][num0][num1] = 1 ;
		LL ans0 , ans1 = 0 , ans2 = 0;
		ans0 = dfs(0 , 0 , 0) ;
		int a = 0 , b = 0 ;
		for(int i = 0 ; i < n ; i++) {
			if(a < num0 && b < num1 && s0[a] + d < s1[b]) {
				a++ ; continue ; 
			}
			if(b < num1) { b++ ; ans1 |= 1llu<<i ; continue ; }
			a++ ;
		}
		a = b = 0 ;
		for(int i = 0 ; i < n ; i++) {
			if(a < num0 && b < num1 && s1[b] + d < s0[a]) {
				ans2 |= 1llu << i ;
				b++ ; continue ;
			}
			if(a < num0) {a++ ; continue ;}
			b++ ; ans2 |= 1llu << i ;
		}
		
		printf("Case %d: %llu %llu %llu\n",++T,f[0][0][0],ans1,ans2) ;
	}
	return 0 ;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值