hdu5803

数位dp

f[i][st][w1][w2]表示到第i位,这一位a,b,c,d的数是否分别要小于ABCD的状态st,w1表示前一位a+c-b-d为几,w2表示a+d-b-c为几

由于前一位差大于等于2后,后面能始终确保a+c>b+d,所以w1, w2状态只有-1,0,1,2四种

注意这时如果按十进制诸位考虑,复杂度为18*9^4*16*4*4会超时

而逐二进制位复杂度为61*2^4*16*4*4,如此可过

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 const int mo=1e9+7;
 6 int f[62][16][4][4],g[4][62];
 7 ll a,b,c,d;
 8 
 9 int dfs(int i,int st,int w1,int w2)
10 {
11     if (i==-1)
12     {
13         if (w1>=2&&w2>=1) return 1;
14         else return 0;
15     }
16     if (f[i][st][w1][w2]>-1) return f[i][st][w1][w2];
17     int s=0,r[4];
18     for (int j=0; j<4; j++) r[j]=((st>>j)&1)?1:g[j][i];
19     for (int a0=0; a0<=r[0]; a0++)
20         for (int b0=0; b0<=r[1]; b0++)
21             for (int c0=0; c0<=r[2]; c0++)
22                 for (int d0=0; d0<=r[3]; d0++)
23                 {
24                     int nw=st,q1,q2;
25                     int l=a0+c0+(w1-1)*2-b0-d0;
26                     if (l<-1) continue; else q1=(l>1)?2:l;
27                     l=a0+d0+(w2-1)*2-b0-c0;
28                     if (l<-1) continue; else q2=(l>1)?2:l;
29                     if (a0<r[0]) nw|=1;
30                     if (b0<r[1]) nw|=2;
31                     if (c0<r[2]) nw|=4;
32                     if (d0<r[3]) nw|=8;
33                     s=(s+dfs(i-1,nw,q1+1,q2+1))%mo;;
34                 }
35 
36     f[i][st][w1][w2]=s;
37     return s;
38 }
39 
40 void work(ll x,int w)
41 {
42     int t=0;
43     while (x)
44     {
45         g[w][t++]=x%2;
46         x/=2;
47     }
48 }
49 
50 int main()
51 {
52     int cas;
53     scanf("%d",&cas);
54     while (cas--)
55     {
56         scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
57         memset(g,0,sizeof(g));
58         work(a,0); work(b,1); work(c,2); work(d,3);
59         memset(f,255,sizeof(f));
60         printf("%d
",dfs(61,0,1,1));
61     }
62 }
View Code
原文地址:https://www.cnblogs.com/phile/p/6399461.html