Description
给出四个整数A,B,C,D,问有多少四元组(a,b,c,d)满足a+c>b+d,a+d≥b+c,其中0<=a<=A,0<=b<=B,0<=c<=C,0<=d<=D,
Input
第一行一整数T表示用例组数,每组用例输入四个整数A,B,C,D
Output
对于每组用例,输出满足条件的四元组个数
Sample Input
1
2 1 1 1
Sample Output
10
Solution
将a,b,c,d拆成二进制用数位DP做,若a和c已经填的位与b和d已经填的位的差值大与等于2那么之后的较低位怎么填都满足a+c>b+d的条件,若小于等于-2那么之后的较低位怎么填都不会满足a+c>b+d,至于a+d≥b+c同理,所以每次枚举范围在-2~2之间
Code
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
#define mod 1000000007
int T,dp[66][16][5][5];
ll a[4];
int dfs(int pos,int v1,int v2,int fp)
{
if(pos<0)
{
if(v1>0&&v2>=0)return 1;
return 0;
}
if(dp[pos][fp][v1+2][v2+2]!=-1)return dp[pos][fp][v1+2][v2+2];
int ans=0,up[4];
for(int i=0;i<4;i++)
{
if(fp&(1<<i))up[i]=1;
else up[i]=(a[i]>>pos)&1;
}
for(int i=0;i<=up[0];i++)
{
for(int j=0;j<=up[1];j++)
{
for(int k=0;k<=up[2];k++)
{
for(int l=0;l<=up[3];l++)
{
int w1=v1*2+i+k-j-l;
int w2=v2*2+i+l-j-k;
if(w1<=-2)continue;
if(w2<=-2)continue;
if(w1>2)w1=2;
if(w2>2)w2=2;
int temp=fp;
if(i!=up[0])temp|=1;
if(j!=up[1])temp|=2;
if(k!=up[2])temp|=4;
if(l!=up[3])temp|=8;
ans+=dfs(pos-1,w1,w2,temp),ans%=mod;
}
}
}
}
return dp[pos][fp][v1+2][v2+2]=ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(dp,-1,sizeof(dp));
for(int i=0;i<4;i++)scanf("%lld",&a[i]);
printf("%d\n",dfs(60,0,0,0));
}
return 0;
}