TopCoder SRM 595 Div2 第3题

类型:数论  难度:2.5

题意:给出三个数A,B,C,求(X,Y)的数目,(X,Y)满足 0 <= X <= A, 0 <= Y <= B,且(X异或Y)<=C

分析:最近碰到很多计数题,这题花了不少时间,方法有点麻烦。。

先将A,B,C转换为二进制存入数组,dp[pos][ia][ib][ic]表示第pos位A,B,C是否置定,ia,ib,ic为0,1,0表示未置定,1表示置定。

ia置定即该位A可任取0,1,置定的原因是:A[k]=1,而实际取0,其中k>pos。即比pos高的位上A实际为1,但是取了0,故A后边的位可随意取值,称为置定。

给出这个概念后,分情况写出状态转移方程,讨论ia,ib,ic的所有取值组合(000-111)8种情况,每种情况中,当ia,ib,ic为0时,还要讨论A[pos],B[pos],C[pos]的取值,分别写方程。

 

代码如下:

#include<string>
#include<cstdio>
#include<vector>
#include<cstring>
#include<map>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;

const int maxM = 40;

class LittleElephantAndXor
{ 
	int a[maxM],b[maxM],c[maxM];
	long long dp[maxM][2][2][2];
	 
	public:
		void intToBit(int arr[],int n)
		{
			for(int i=0; n; i++,n>>=1)
			{
				arr[i] = n&1;
			}
		}
		
		long long mypow(long long x,int y)
		{
			long long ans = 1;
			while(y--) ans *= x;
			return ans;
		}
		
		long long fun(int pos,bool ia,bool ib,bool ic)
		{
			//printf("%d %d %d %d\n",pos,ia,ib,ic);
			if(pos < 0) return 1;
			if(dp[pos][ia][ib][ic] >= 0) return dp[pos][ia][ib][ic];
			
			long long ans,two = 2;
			if(ia && ib && ic)
				ans = mypow(two,two*(pos+1));
			else if(ia && ib)
			{
				if(c[pos]) ans = two*(fun(pos-1,1,1,0)+fun(pos-1,1,1,1));
				else ans = two*fun(pos-1,1,1,0);
			}
			else if(ia && ic)
			{
				if(b[pos]) ans = two*(fun(pos-1,1,0,1)+fun(pos-1,1,1,1));
				else ans = two*fun(pos-1,1,0,1);
			}
			else if(ib && ic)
			{
				if(a[pos]) ans = two*(fun(pos-1,0,1,1)+fun(pos-1,1,1,1));
				else ans = two*fun(pos-1,0,1,1);
			}
			else if(ia)
			{
				if(b[pos])
				{
					if(c[pos]) ans = fun(pos-1,1,0,0) + fun(pos-1,1,1,0) + fun(pos-1,1,0,1) + fun(pos-1,1,1,1);
					else ans = fun(pos-1,1,0,0) + fun(pos-1,1,1,0);
				}
				else
				{
					if(c[pos]) ans = fun(pos-1,1,0,0) + fun(pos-1,1,0,1);
					else ans = fun(pos-1,1,0,0);
				}
			}
			else if(ib)
			{
				if(a[pos])
				{
					if(c[pos]) ans = fun(pos-1,0,1,0) + fun(pos-1,1,1,0) + fun(pos-1,0,1,1) + fun(pos-1,1,1,1);
					else ans = fun(pos-1,0,1,0) + fun(pos-1,1,1,0);
				}
				else
				{
					if(c[pos]) ans = fun(pos-1,0,1,0) + fun(pos-1,0,1,1);
					else ans = fun(pos-1,0,1,0);
				}
			}
			else if(ic)
			{
				if(a[pos])
				{
					if(b[pos]) ans = fun(pos-1,0,1,1) + fun(pos-1,1,1,1) + fun(pos-1,1,0,1) + fun(pos-1,0,0,1);
					else ans = fun(pos-1,0,0,1) + fun(pos-1,1,0,1);
				}
				else
				{
					if(b[pos]) ans = fun(pos-1,0,0,1) + fun(pos-1,0,1,1);
					else ans = fun(pos-1,0,0,1);
				}
			}
			else
			{
				if(a[pos])
				{
					if(b[pos])
					{
						if(c[pos]) ans = fun(pos-1,0,0,1) + fun(pos-1,1,1,1) + fun(pos-1,1,0,0) + fun(pos-1,0,1,0);
						else ans = fun(pos-1,0,0,0) + fun(pos-1,1,1,0);
					}
					else
					{
						if(c[pos]) ans = fun(pos-1,1,0,1) + fun(pos-1,0,0,0);
						else ans = fun(pos-1,1,0,0);
					}
				}
				else
				{
					if(b[pos])
					{
						if(c[pos]) ans = fun(pos-1,0,0,0) + fun(pos-1,0,1,1);
						else ans = fun(pos-1,0,1,0);
					}
					else
					{
						if(c[pos]) ans = fun(pos-1,0,0,1);
						else ans = fun(pos-1,0,0,0);
					}
				}
			}
			dp[pos][ia][ib][ic] = ans;
			//printf("%d %d %d %d %lld\n",pos,ia,ib,ic,dp[pos][ia][ib][ic]);
			return dp[pos][ia][ib][ic];
		}
		
		long long getNumber(int A, int B, int C)
		{
			memset(a,0,sizeof(a));
			memset(b,0,sizeof(b));
			memset(c,0,sizeof(c));
			intToBit(a,A);
			intToBit(b,B);
			intToBit(c,C);
			
			memset(dp,-1,sizeof(dp));
			return fun(maxM-1,0,0,0);
		}
};

int main()
{
	LittleElephantAndXor t; 
	cout<<t.getNumber(5e8,2e8,1)<<endl;
}





 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值