HDU 5803 Zhu's Math Problem(数位DP)

时间:2022-12-16 10:41:37

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;
}