参考博客:https://blog.csdn.net/u013534123/article/details/98877628#commentsedit
题目:
解题思路:
涉及到位运算,把A,B,C转化成二进制,记录每位上的值,最低位下标是1。
数位dp, 从高位开始处理,,stax(sta1,sta2)有3种状态:0-还存在满足条件x的可能性,1-已经确定满足条件x,2-已经确定不满足条件x,lim1,lim2表示x,ypos位前面的位上的数有没有达到限制。
剪枝+记忆化,注意返回值的判断条件,剩下的就和普通的数位dp差多了。
注意:题目要求x和y必须大于0,但是在数位dp的dfs里加大于0的判断稍微有点麻烦,可以在最后输出的时候处理一下。数位dp得到的结果是(0≤x≤A,0≤y≤B)对应的结果,应该减去(x=0,0≤y≤B)对应的结果,再减去(0≤x≤A,y=0)最后减去(x=0,y=0)的结果。(这里的字母符号和代码里的有点出入,莫事,小问题)
ac(?)代码:
没有账号,没法提交,枯了?
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[35][4][4][2][2], pow2[40], vala[40], valb[40];
int a[40], b[40], c[40];
int x, y, z;
int init()
{
memset(dp, -1, sizeof dp);
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
memset(c, 0, sizeof c);
memset(vala, 0, sizeof vala);
memset(valb, 0, sizeof valb);
int X = x, Y = y, Z = z;
int cnt1 = 0, cnt2 = 0, cnt3 = 0;
while(X) a[++cnt1] = X&1, X >>= 1;
while(Y) b[++cnt2] = Y&1, Y >>= 1;
while(Z) c[++cnt3] = Z&1, Z >>= 1;
int maxt = max(cnt1, max(cnt2, cnt3));
for(int i = 1; i <= maxt; i++)
{
for(int j = i; j >= 1; j--) // i-1
{
vala[i] = vala[i] << 1 | a[j];
valb[i] = valb[i] << 1 | b[j];
}
}
return maxt;
}
void get_pow2()
{
pow2[0] = 1;
for(int i = 1; i <= 32; i++)
pow2[i] = pow2[i - 1] * 2;
}
ll dfs(int pos, int sta1, int sta2, bool lim1, bool lim2) //stax = 0 还可能存在满足条件x的情况,= 1,满足条件x, = 2, 不满足条件x(<成>这种)
{
if(pos == 0) return sta1 == 1 || sta2 == 1; // 满足条件之一就返回1
if(sta1 == 2 && sta2 == 2) return 0;
if(sta1 == 1 || sta2 == 1)
{
ll s1 = lim1 ? vala[pos] + 1 : pow2[pos]; // 如果pos前面的位上的数都已经达到了最大值
ll s2 = lim2 ? valb[pos] + 1 : pow2[pos];
return s1 * s2;
}
if(dp[pos][sta1][sta2][lim1][lim2] != -1) return dp[pos][sta1][sta2][lim1][lim2];
int up1 = lim1 ? a[pos] : 1, up2 = lim2 ? b[pos] : 1;
ll sum = 0;
for(int i = 0; i <= up1; i++)
{
for(int j = 0; j <= up2; j++)
{
int v1 = i & j, v2 = i ^ j, sta11 = sta1, sta22 = sta2; // 应该v1 > C, v2 < C
// 都不满足和至少有一个满足都处理了,只剩下00 ,02(20) 这种情况了
if((v1 < c[pos] || sta1 == 2) && (v2 > c[pos] || sta2 == 2)) continue;
if(sta1 == 0) // 上一位 x,y对应位上的值&后和z对应位上的值相同,还存在有解的可能性
{
if(v1 < c[pos]) sta11 = 2;
else if(v1 > c[pos]) sta11 = 1;
else sta11 = 0;
}
if(sta2 == 0)
{
if(v2 > c[pos]) sta22 = 2;
else if (v2 < c[pos]) sta22 = 1;
else sta22 = 0;
}
//回溯时还要用到原来的值
sum += dfs(pos - 1, sta11, sta22, lim1 && i == a[pos], lim2 && j == b[pos]);
}
}
dp[pos][sta1][sta2][lim1][lim2] = sum;
return sum;
}
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
get_pow2();
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d %d %d", &x, &y, &z);
int len = init();
printf("%lld\n", dfs(len, 0, 0, true, true) - min(x, z - 1) - min(y, z - 1) - 1);
}
return 0;
}