2013年南京邀请赛的铜牌题。。。做的很是伤心,另外有两个不太好想到的地方。。。。a 可以等于零,另外a到b的累加和比较大,大约在2^70左右。
首先说一下解题思路。
首先统计出每一位的1的个数,然后统一进位。
设最低位为1,次低位为2,依次类推,ans[]表示这一位上有多少个1,那么有
sum += ans[i]/2,ans[i+1] += ans[i]/2;
sum即为答案。
好了,现在问题转化成怎么求ans[]了。
打表查规律比较神奇,上图不说话。
打表的代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define _INF 0x3f3f3f3f
#define Mod 9999991
#define lowbit(x) (x&(-x))
using namespace std;
void out(int x)
{
while(x)
{
printf("%d",x&1);
x >>= 1;
}
}
int main()
{
for(int i = 1;i <= 100; ++i)
{
printf("i = %3d : ",i);
out(i);
puts("");
}
return 0;
}
好了,重头戏来了,这个数位DP做的还是很有成就感的。
记忆化搜索 + bfs推送
昨天其实想这个思路了。。。不过当时比较着急没写出来,心态是个很重要的东西。
记忆化搜索部分dp[sta][site][dig] 第一维表示是否到达上限,site表示第几位,dig表示是1还是0。
那么site == 1时,也就是说最高位记录的信息是正确的,但是其他的就不是想要的了。因为dp[sta][site][sta] 表示当前位到最低位的方案数。
所以说要把最高位的答案推送下去。
推送很简单,每种状态最多只会由两种子状态得到,所以按比例推送一下就行了。
详见代码。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define _INF 0x3f3f3f3f
#define Mod 9999991
#define lowbit(x) (x&(-x))
using namespace std;
_LL dp[2][105][2],dp1[2][105][2];
_LL up[105];
_LL ansa[105],ansb[105];
_LL dfs(_LL sta,_LL site,_LL dig)
{
if(dp[sta][site][dig] != -1)
return dp[sta][site][dig];
if(site == 100)
{
dp[sta][site][dig] = 1;
return 1;
}
dp[sta][site][dig] = 0;
if(sta == 0)
{
dp[sta][site][dig] = dfs(0,site+1,0) + dfs(0,site+1,1);
}
else
{
if(up[site+1] == 1)
{
dp[sta][site][dig] = dfs(1,site+1,1) + dfs(0,site+1,0);
}
else
{
dp[sta][site][dig] = dfs(1,site+1,0);
}
}
return dp[sta][site][dig];
}
void Cal(_LL x,_LL *ans)
{
_LL temp = x,len = 100;
memset(ans,0,sizeof(_LL)*(102));
if(x == 0)
return ;
while(temp)
{
up[len--] = temp%2;
temp /= 2;
}
len++;
memset(dp,-1,sizeof(dp));
dfs(1,len,1);
dfs(0,len,0);
_LL i;
memset(dp1,0,sizeof(dp1));
dp1[1][len][1] = max((_LL)0,dp[1][len][1]);
dp1[1][len][0] = max((_LL)0,dp[1][len][0]);
dp1[0][len][1] = max((_LL)0,dp[0][len][1]);
dp1[0][len][0] = max((_LL)0,dp[0][len][0]);
for(_LL site = len;site <= 99; ++site)
{
dp1[0][site+1][1] += dp1[0][site][1]*dp[0][site+1][1]/(dp[0][site+1][1] + dp[0][site+1][0]);
dp1[0][site+1][1] += dp1[0][site][0]*dp[0][site+1][1]/(dp[0][site+1][1] + dp[0][site+1][0]);
dp1[0][site+1][0] += dp1[0][site][1]*dp[0][site+1][0]/(dp[0][site+1][1] + dp[0][site+1][0]);
dp1[0][site+1][0] += dp1[0][site][0]*dp[0][site+1][0]/(dp[0][site+1][1] + dp[0][site+1][0]);
if(up[site+1] == 1)
{
if(up[site] == 1)
{
dp1[1][site+1][1] += dp1[1][site][1]*dp[1][site+1][1]/(dp[1][site+1][1] + dp[0][site+1][0]);
dp1[0][site+1][0] += dp1[1][site][1]*dp[0][site+1][0]/(dp[1][site+1][1] + dp[0][site+1][0]);
}
else
{
dp1[1][site+1][1] += dp1[1][site][0]*dp[1][site+1][1]/(dp[1][site+1][1] + dp[0][site+1][0]);
dp1[0][site+1][0] += dp1[1][site][0]*dp[0][site+1][0]/(dp[1][site+1][1] + dp[0][site+1][0]);
}
}
else
{
dp1[1][site+1][0] = dp1[1][site][0] + dp1[1][site][1];
}
}
for(i = len;i <= 100; ++i)
{
ans[i] = max((_LL)0,dp1[1][i][1]) + max((_LL)0,dp1[0][i][1]);
}
}
int main()
{
_LL a,b,i;
while(scanf("%I64d %I64d",&a,&b) != EOF)
{
Cal(b,ansb);
Cal(max((_LL)0,a-1),ansa);
_LL sum = 0;
for(i = 100;i >= 1; --i)
{
sum += (ansb[i]-ansa[i])/2;
ansb[i-1] += (ansb[i]-ansa[i])/2;
}
printf("%I64d\n",sum);
}
return 0;
}