洛谷CF809C Find a car(數位DP)

洛谷題目傳送門c++

經過瞪眼法發現,\(a_{i,j}=(i-1)\text{ xor }(j-1)+1\)spa

二維差分一下,咱們只要能求\(\sum\limits_{i=0}^x\sum\limits_{j=0}^y[i\text{ xor }j\le k]\)就行了。code

比較套路的數位DP。get

從高位往低位作,設\(f[t][0/1][0/1][0/1]\)表示到第\(t\)位,\(i,j,i\text{ xor }j\)已肯定的值是否卡到\(x,y,k\)\(t\)位的上界的方案數和權值和。it

每一位的轉移都是一個小討論:若是以前卡到上界,這一位能夠接着卡,或者若是這一位的上界是\(1\),就能夠填\(0\)轉移到不卡上界。若是以前不卡了,那麼這一位隨便選。class

注意到最開始的式子裏有一個\(+1\),因此要輸出\(\sum\)權值和+方案數。gc

下面的代碼使用了壓位和define可能會比較醜im

#include<bits/stdc++.h>
#define R register int
using namespace std;
const int YL=1e9+7;
int t,fc[8],fs[8],gc[8],gs[8];
inline int in(){R x;scanf("%d",&x);return x;}
inline void M(R&x){if(x>=YL)x-=YL;}
#define T(x,u,v) if(i>1||w==x)Trans(i>>1,li,u,v,i>1?w^x:w)
void Trans(R i,R li,R u,R v,R w){//暴搜轉移
    if(!i){
        if(w)gs[v]=(gs[v]+fc[u]*(long long)t)%YL;
        return M(gc[v]+=fc[u]),M(gs[v]+=fs[u]);
    }
    if(i&li){T(0,u,v|i);T(1,u,v);}//討論開始
    else T(0,u,v);
    T(0,u|i,v|i);
    T(1,u|i,v|i);
}
int Dp(R n,R m,R k){
    if(n<0||m<0)return 0;
    memset(fc,0,32);fc[0]=1;
    memset(fs,0,32);
    for(t=1<<30;t;t>>=1){
        Trans(4,!!(n&t)*4|!!(m&t)*2|!!(k&t),0,0,0);
        memcpy(fc,gc,32),memset(gc,0,32);
        memcpy(fs,gs,32),memset(gs,0,32);
    }
    R s=0;
    for(R i=0;i<8;++i)M(s+=fs[i]),M(s+=fc[i]);
    return s;
}
int main(){
    for(R q=in();q--;){
        R x1=in()-2,y1=in()-2,x2=in()-1,y2=in()-1,k=in()-1;
        cout<<((Dp(x2,y2,k)-Dp(x1,y2,k)-Dp(x2,y1,k)+Dp(x1,y1,k))%YL+YL)%YL<<endl;
    }
    return 0;
}
相關文章
相關標籤/搜索