Xor HDU - 6899
题意:
给你A,B,K,W,问现在有多少个(x,y)满足下列形式?
- x,y都是整数
- x∈[0,A],y∈[0,B]
- |x-y|<=k
- x xor y<=W
题解:
数位dp
对于第1,2,4都是经典的数位dp转移
对于第三点怎么转移?
我们将绝对值拆开,得到x−y<=k,y−x<=kx-y<=k,y-x<=kx−y<=k,y−x<=k
整理下:k+y−x>=0,k−y+x>=0k+y-x>=0,k-y+x>=0k+y−x>=0,k−y+x>=0
现在我们要让k+y-x>=0(暂先考虑这一个)
数位dp是按照每一位去考虑,那么k,x,y都是只能取0,1,那么也就是说k+y-x的取值范围是[-1,1],但是与异或不同,我们这个式子不能光看二进制运算,因为每位之间是由联系的,所以我们可以在转移时记录上个值的情况,用k1来记录,对于当前的值就是k1 * 2+val,(乘2是因为我们是二进制拆分的,所有还原时要乘回去)。如果k1<=-2,那必然没解,因为k1乘2后变成-4,而当前为k+y-x最大才是1,这样传下去还是负的,无法变正。如果k1>=1是一定有解的,因为怎么都是正数
与常规数位dp不同,本题牵扯了进位情况,第一次见,记录一下
详细看代码
代码:
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{x= 0;char c= getchar();bool flag= 0;while (c < '0' || c > '9')flag|= (c == '-'), c= getchar();while (c >= '0' && c <= '9')x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();if (flag)x= -x;read(Ar...);
}
template <typename T> inline void write(T x)
{if (x < 0) {x= ~(x - 1);putchar('-');}if (x > 9)write(x / 10);putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#elsestartTime = clock ();freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#elseendTime= clock();printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn=50;
ll dp[maxn][5][5][2][2][2];
ll a[maxn],b[maxn],k[maxn],w[maxn];
int p=1;//偏移量
ll dfs(int len,int k1,int k2,int flag1,int flag2,int flag3){if(k1<=-2||k2<=-2)return 0; if(len==-1)return (k1>=0&&k2>=0);if(dp[len][k1+p][k2+p][flag1][flag2][flag3]!=-1)return dp[len][k1+p][k2+p][flag1][flag2][flag3];int up1=flag1?a[len]:1;int up2=flag2?b[len]:1;int up3=flag3?w[len]:1;ll ans=0;for(int i=0;i<=up1;i++){for(int j=0;j<=up2;j++){if((i^j)>up3)continue;ans+=dfs(len-1,min(k1*2+i-j+k[len],1ll),min(k2*2+j-i+k[len],1ll),flag1&&(i==up1),flag2&&(j==up2),flag3&&((i^j)==w[len]));}}return dp[len][k1+p][k2+p][flag1][flag2][flag3]=ans;
}
ll solve(int A,int B,int K,int W){memset(dp,-1,sizeof(dp));for(int i=0;i<=30;i++){a[i]=(A&1);A>>=1;b[i]=(B&1);B>>=1;k[i]=(K&1);K>>=1;w[i]=(W&1);W>>=1;}ll ans=dfs(30,0,0,1,1,1);return ans;
}
int main()
{rd_test();int t;read(t);while(t--){ll A,B,K,W;read(A,B,K,W);cout<<solve(A,B,K,W)<<endl; }//Time_test();
}