UVA 1228 Integer Transmission

这本来是道简单的DP题目的。。

但是拖拖拉拉做了很久 = =

该题题意是传输一个最大64位的二进制数,传输过程中每个0或1有 1 ~ d+1 秒的随机延迟。然后求接收方能获得的最大值与最小值,还有可能接收到的二进制数的种数。

这里分析一下,最大值和最小值只要贪心一下就可以得到了,比较容易(求最大值让1尽量考前,求最小值让0尽量靠前)。但是可能获得的二进制数的种数,这个需要用DP解决,差不多是这道题的重点了。

因为二进制的特殊性,要不就是1要不就是0,所以直接分成两类来观察就可以了。Dp[ i ][ j ]就代表第 i 个1前有 j 个0的方案种数,根据插入第 i+1 个1和第 i 个1之间的0的个数IN,可以更新出Dp[ i+1 ][ j+IN ] ;这里可能插入的0的个数需要根据最大延迟 d 来进行判断。

那么问题就都解决了~

#include <stdio.h>
#include <string.h>

typedef unsigned long long LL;

const int MAXM = 110;
const LL F = 1;

int Num,Limit;
LL Data,All;

LL Min,Max;
LL Dp[MAXM][MAXM];

int Queue[MAXM];
int Zero[MAXM];
int One[MAXM];

void Get_Edge(LL Type,LL &Ans)
{
	int Start=0,End=0,hav=Num-1;
	for(int i=Num-1;i>=0;i--)
	{
		if(((Data>>i)&F)==Type)
		{
			Ans|=Type<<hav;
			hav--;
		}
		else
		{
			Queue[End++]=i;
		}
		if((Start<End)&&(Queue[Start]==i+Limit))
		{
			Ans|=(Type^F)<<hav;
			Start++;hav--;
		}
	}
	while(hav>=0)
	{
		Ans|=(Type^F)<<hav;
		hav--;
	}
}

void Pushup(int pos,int front)
{
	int next=pos+1,in=1;
	while(Zero[front+in]-One[next]>Limit)
	{
		in++;
	}
	Dp[next][front+in-1]+=Dp[pos][front];
	while(One[next]-Zero[front+in]<=Limit)
	{
		Dp[next][front+in]+=Dp[pos][front];
		in++;
	}
}

void Get_Way()
{
	int one=1,zero=1;
	memset(Dp,0,sizeof(Dp));
	for(int i=Num-1;i>=0;i--)
	{
		if((Data>>i)&F)
		{
			One[one++]=i;
		}
		else
		{
			Zero[zero++]=i;
		}
	}
	Zero[zero]=-MAXM;
	if(one==1||zero==1)
	{
		All=1;
		return;
	}
	Dp[0][0]=1;
	Pushup(0,0);
	for(int i=1;i<one-1;i++)
	{
		for(int t=0;t<zero;t++)
		{
			if(Dp[i][t])
			{
				Pushup(i,t);
			}
		}
	}
	All=0;
	for(int t=0;t<zero;t++)
	{
		All+=Dp[one-1][t];
	}
}

int main()
{
	int Case=1;
	while(scanf("%d",&Num),Num)
	{
		scanf("%d %llu",&Limit,&Data);
		Min=Max=0;
		Get_Edge(0,Min);
		Get_Edge(1,Max);
		Get_Way();
		printf("Case %d: %llu %llu %llu\n",Case++,All,Min,Max);
	}
}


有个郁闷的地方是,输入输出应该是%llu。。。。不是%lld(我会说我WA了好几次么)

(╯‵□′)╯︵┻━┻(╯‵□′)╯︵┻━┻(╯‵□′)╯︵┻━┻


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值