题意:
给出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
T≤1000
0≤A,B,C,D≤10^18
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#define N 100
#define mmod 1000000007
#define LL long long
using namespace std;
int f[N][2][2][2][2][4][4];
int a[N],b[N],c[N],d[N],al,bl,cl,dl,n,ans;
void upd(int &x,int y)
{
x=(x+y)%mmod;
}
int make(int s,int d)
{
if(s==2) return 2;
if(s==3)
{
if(d==2) return 0;
if(d==1) return 3;
return -1;
}
if(s==1)
{
if(d==-2) return 0;
if(d==-1) return 1;
return 2;
}
if(d==-2) return -1;
if(d==-1) return 3;
return d;
}
void dp()
{
for(int i=0;i<=n;i++)
for(int o1=0;o1<=1;o1++)
for(int o2=0;o2<=1;o2++)
for(int o3=0;o3<=1;o3++)
for(int o4=0;o4<=1;o4++)
for(int s1=0;s1<=3;s1++)
for(int s2=0;s2<=3;s2++)
f[i][o1][o2][o3][o4][s1][s2]=0;
f[0][0][0][0][0][0][0]=1;
for(int i=0;i<n;i++)
for(int o1=0;o1<=1;o1++)
for(int o2=0;o2<=1;o2++)
for(int o3=0;o3<=1;o3++)
for(int o4=0;o4<=1;o4++)
for(int s1=0;s1<=3;s1++)
for(int s2=0;s2<=3;s2++)
{
if(f[i][o1][o2][o3][o4][s1][s2]==0) continue;
for(int d1=0;d1<=1;d1++)
{
int t1=o1;
if(o1==0 && d1>a[i+1]) continue;
if(d1<a[i+1]) t1=1;
for(int d2=0;d2<=1;d2++)
{
int t2=o2;
if(o2==0 && d2>b[i+1]) continue;
if(d2<b[i+1]) t2=1;
for(int d3=0;d3<=1;d3++)
{
int t3=o3;
if(o3==0 && d3>c[i+1]) continue;
if(d3<c[i+1]) t3=1;
for(int d4=0;d4<=1;d4++)
{
int t4=o4;
if(o4==0 && d4>d[i+1]) continue;
if(d4<d[i+1]) t4=1;
int h1,h2;
h1=make(s1,d1+d3-d2-d4);
h2=make(s2,d1+d4-d2-d3);
if(h1==-1 || h2==-1) continue;
upd(f[i+1][t1][t2][t3][t4][h1][h2],f[i][o1][o2][o3][o4][s1][s2]);
}
}
}
}
}
}
int main()
{
int z;scanf("%d",&z);
while(z--)
{
n=al=bl=cl=dl=0;
LL t;scanf("%lld",&t);
while(t) {a[++al]=t%2;t/=2;}
for(int i=1;i<=al/2;i++) swap(a[i],a[al-i+1]);
n=max(n,al);
scanf("%lld",&t);
while(t) {b[++bl]=t%2;t/=2;}
for(int i=1;i<=bl/2;i++) swap(b[i],b[bl-i+1]);
n=max(n,bl);
scanf("%lld",&t);
while(t) {c[++cl]=t%2;t/=2;}
for(int i=1;i<=cl/2;i++) swap(c[i],c[cl-i+1]);
n=max(n,cl);
scanf("%lld",&t);
while(t) {d[++dl]=t%2;t/=2;}
for(int i=1;i<=dl/2;i++) swap(d[i],d[dl-i+1]);
n=max(n,dl);
for(int i=al;i>=1;i--) a[i+n-al]=a[i];
for(int i=1;i<=n-al;i++) a[i]=0;
for(int i=bl;i>=1;i--) b[i+n-bl]=b[i];
for(int i=1;i<=n-bl;i++) b[i]=0;
for(int i=cl;i>=1;i--) c[i+n-cl]=c[i];
for(int i=1;i<=n-cl;i++) c[i]=0;
for(int i=dl;i>=1;i--) d[i+n-dl]=d[i];
for(int i=1;i<=n-dl;i++) d[i]=0;
dp();
ans=0;
for(int a=0;a<=1;a++)
for(int b=0;b<=1;b++)
for(int c=0;c<=1;c++)
for(int d=0;d<=1;d++)
for(int o1=1;o1<=2;o1++)
for(int o2=0;o2<=2;o2++)
upd(ans,f[n][a][b][c][d][o1][o2]);
printf("%d\n",ans);
}
return 0;
}
题解:
一开始觉得是分类讨论,化柿子化得有点想吐。。然后看了题解,说可以数位dp,那就dp吧。。
注意10^4枚举每位太慢,转成二进制后就是2^4的了