zoukankan      html  css  js  c++  java
  • 状压dp

    bzoj3591 最长上升子序列(!!!

    题目大意:求1~n的排列满足其中一个最长上升子序列是给定数列的个数。

    思路:考虑nlogn单调栈求lis,可以用gi[i][j]表示栈中状态是i的时候加入j之后栈的状态,可以n^2*2^n预处理。然后考虑dp,fi[i]表示状态是i的dp值,i是个三进制数,0表示没选、1表示选了但不在栈中、2表示在栈中,三进制不好保存,如果分解会tle,所以可以表示成两个二进制数相加,用之前012的意义比较好表示。

    注意:(1)选j的时候,如果j在给定的上升子序列中,要考虑j之前的数要选的要求;

         (2)答案是所有栈中元素为m的和,因为可能某次转移的时候,给定的数就不在栈中了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 15
    #define M 14348907
    using namespace std;
    int gi[N+1][1<<N],fi[M],mi[N+1],ai[1<<N]={0},pre[N],bi[1<<N]={0};
    int main(){
        int i,j,k,p,x,n,m,ans=0;
        scanf("%d%d",&n,&m);
        for (i=0;i<n;++i) pre[i]=-1;
        for (mi[0]=i=1;i<=n;++i) mi[i]=mi[i-1]*3;
        for (x=-1,i=1;i<=m;++i){
            scanf("%d",&j);
            pre[j-1]=x;x=j-1;
        }for (i=0;i<(1<<n);++i)
            for (j=0;j<n;++j){
                if ((i>>j)&1){ai[i]+=mi[j];++bi[i];continue;}
                for (p=i,k=0;k<n;++k)
                    if (((i>>k)&1)&&k>j){
                        p^=1<<k;
                        break;
                    }
                p^=1<<j;
                gi[j][i]=p;
            }
        for (i=0;i<n;++i)
            if (pre[i]<0) fi[mi[i]<<1]=1;
        for (i=1;i<(1<<n);++i)
            for (j=0;j<n;++j){
                if ((i>>j)&1) continue;
                if (pre[j]>=0&&(!((i>>pre[j])&1))) continue;
                for (k=i;k;k=(k-1)&i)
                    if (fi[ai[i]+ai[k]]) fi[ai[i|(1<<j)]+ai[gi[j][k]]]+=fi[ai[i]+ai[k]];
            }
        for(i=1;i<(1<<n);++i)
            if(bi[i]==m) ans+=fi[ai[(1<<n)-1]+ai[i]];
          printf("%d
    ",ans);
    }
    View Code

    轮廓线dp

    bzoj4572 围棋(!!!

    题目大意:已知一些模板(2行c列),对于每种模板,求n*m的棋盘中出现这种模板的棋盘的数量。

    思路:fi[i][j][k][x][y]表示轮廓线到(i,j),k表示轮廓线上的以这个点结尾能否和第一行模板匹配,x、y表示和第一二行模板匹配的kmp到的位置。预处理模板的kmp和每行在i的位置加入一个字母j转移到的gi[i][j]。除了两行都能匹配的状态,其他都可以转移,最后答案就是3^(n*m)-sigma(k=0~(2^m-1),x=0~c,y=0~c)fi[n][m][k][x][y]。

    注意:1)判断两行都匹配的时候,j还要>=c,否则可能出现换行之后匹配一部分的情况。

         2)对kmp要有正确的理解,表示的是匹配的长度,也就是说前i-1位是匹配的,第i位不一定匹配。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 105
    #define M 12
    #define up 7
    #define p 1000000007LL
    #define LL long long
    using namespace std;
    int chin(){
        char ch=getchar();
        while(ch<'A'||ch>'Z') ch=getchar();
        return (ch=='B' ? 2 : (ch=='W'));
    }
    int n,m,c,ai[M],gi[2][M][M],hi[M],fi[2][1<<M][up][up];
    void add(int &x,int y){x+=y;if (x>=p) x-=p;}
    void init(int x){
        int i,j,k;memset(ai,127,sizeof(ai));
        for (i=0;i<c;++i) ai[i]=chin();
        hi[0]=hi[1]=0;
        for (i=1;i<c;++i){
            j=hi[i];
            while(j&&ai[i]!=ai[j]) j=hi[j];
            hi[i+1]=(ai[i]==ai[j] ? ++j : 0);
        }for (i=0;i<=c;++i)
            for (j=0;j<=2;++j){
                k=i;
                while(k&&ai[k]!=j) k=hi[k];
                if (ai[k]==j) ++k;
                gi[x][i][j]=k;
            }
    }
    int dp(){
        int i,j,k,x,y,a,nk,nx,ny,cur,la,ans;
        for (i=0;i<2;++i) init(i);
        cur=0;la=1;
        memset(fi[cur],0,sizeof(fi[cur]));
        fi[cur][0][0][0]=1;
        for (i=1;i<=n;++i)
            for (j=1;j<=m;++j){
                cur^=1;la^=1;
                memset(fi[cur],0,sizeof(fi[cur]));
                for (k=0;k<(1<<m);++k)
                    for (x=0;x<=c;++x)
                        for (y=0;y<=c;++y){
                            if (!fi[la][k][x][y]) continue;
                            for (a=0;a<=2;++a){
                                nk=(k<<1)&((1<<m)-1);
                                nx=gi[0][x][a];
                                ny=gi[1][y][a];
                                if (nx==c) nk^=1;
                                if (j>=c&&ny==c&&((k>>(m-1))&1)) continue;
                                add(fi[cur][nk][nx][ny],fi[la][k][x][y]);
                            }
                        }
            }for (ans=1,i=n*m;i;--i) ans=(int)(3LL*ans%p);
        for (k=0;k<(1<<m);++k)
            for (x=0;x<=c;++x)
                for (y=0;y<=c;++y) add(ans,p-fi[cur][k][x][y]);
        return ans;
    }
    int main(){
        int q;
        scanf("%d%d%d%d",&n,&m,&c,&q);
        while(q--) printf("%d
    ",dp());
    }
    View Code

    插头dp

    对于网格中的dp可以用轮廓线,如果有一些格子不能走就可以用插头dp了。

    bzoj2331 地板

    题目大意:用L型铺地n*m,有一些格子不能铺,求方案数。

    思路:fi[i][j][s]表示铺到(i,j),轮廓线状态s,0表示没有插头,1表示插头没拐弯,2表示插头拐弯了,手动枚举转移。

    注意:(1)按四进制好写;

       (2)因为实际状态和四进制的差很多,所以用hash表来存储,防止mle和tle,同时使用滚动数组。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 105
    #define M 200000
    #define uu 50000
    #define pp 20110520
    using namespace std;
    int ai[N][N],fi[2][M]={0},point[uu],next[M],en[M],ha[2][M],tot[2],bt[N],
        nm,n,m,cur,la;
    int in(){
        char ch=getchar();
        while(ch!='_'&&ch!='*') ch=getchar();
        return ch=='*';}
    void add(int s,int gi){
        int i,x=s%uu;
        for (i=point[x];i;i=next[i])
            if (ha[cur][en[i]]==s){
                fi[cur][en[i]]=(fi[cur][en[i]]+gi)%pp;
                return;
            }
        ha[cur][++tot[cur]]=s;fi[cur][tot[cur]]=gi;
        next[++nm]=point[x];point[x]=nm;en[nm]=tot[cur];}
    void dp(){
        int i,j,k,p,q,s,gi,ji;cur=1;la=0;
        tot[cur]=1;en[1]=0;ji=3;
        ha[cur][1]=0;fi[cur][1]=1;
        for (i=0;i<N;++i) bt[i]=i<<1;
        for (i=1;i<=n;++i){
            for (j=1;j<=tot[cur];++j) ha[cur][j]=(ha[cur][j]<<2)&((1<<bt[m+1])-1);
            for (j=1;j<=m;++j){
                cur^=1;la^=1;
                tot[cur]=nm=0;
                memset(fi[cur],0,sizeof(fi[cur]));
                memset(point,0,sizeof(point));
                for (k=tot[la];k;--k){
                    s=ha[la][k];gi=fi[la][k];
                    if (!gi) continue;
                    p=(s>>bt[j-1])&ji;
                    q=(s>>bt[j])&ji;
                    if (ai[i][j]){
                        if (!p&&!q) add(s,gi);
                    }else if (!p&&!q){
                        if (!ai[i+1][j]) add(s+(1<<bt[j-1]),gi);
                        if (!ai[i][j+1]) add(s+(1<<bt[j]),gi);
                        if (!ai[i+1][j]&&!ai[i][j+1]) add(s+(1<<(bt[j-1]+1))+(1<<(bt[j]+1)),gi);
                    }else if (!p){
                        s-=(1<<bt[j])*q;
                        if (q==1){
                            if (!ai[i][j+1]) add(s+(1<<(bt[j]+1)),gi);
                            if (!ai[i+1][j]) add(s+(1<<bt[j-1]),gi);
                        }else{
                            add(s,gi);
                            if (!ai[i+1][j]) add(s+(1<<(bt[j-1]+1)),gi);
                        }
                    }else if (!q){
                        s-=(1<<bt[j-1])*p;
                        if (p==1){
                            if (!ai[i][j+1]) add(s+(1<<bt[j]),gi);
                            if (!ai[i+1][j]) add(s+(1<<(bt[j-1]+1)),gi);
                        }else{
                            add(s,gi);
                            if (!ai[i][j+1]) add(s+(1<<(bt[j]+1)),gi);
                        }
                    }else if (p==1&&q==1){
                        s-=(1<<bt[j-1])+(1<<bt[j]);
                        add(s,gi);
                    }
                }
            }
        }
    }
    int main(){
        int i,j;scanf("%d%d",&n,&m);
        memset(ai,127,sizeof(ai));
        if (n<m){
            for (i=1;i<=n;++i)
                for (j=1;j<=m;++j) ai[j][i]=in();
            swap(n,m);
        }else
            for (i=1;i<=n;++i)
                for (j=1;j<=m;++j) ai[i][j]=in();
        dp();printf("%d
    ",fi[cur][1]);
    }
    View Code

    bzoj1187 神奇游乐园

    题目大意:在n*m的网格中选一条回路,使权值和最大。

    思路:状态同上,用括号序列表示法的三进制(0表示没有,1表示左括号,2表示右括号)。

    注意:(1)每个位置的0都是0;

       (2)在这个格子是左插头是左括号、上插头是右括号的时候说明在这个点形成回路(如果s中还有其他插头说明有多个回路,状态不合法,不能更新答案)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 105
    #define M 10
    #define uu 20000
    #define ji 3
    using namespace std;
    int ai[N][M],fi[2][uu],bt[M],n,m,cur,la,ans,inf,gi[uu],pre[uu][M],suc[uu][M];
    bool vi[uu]={false};
    inline void add(int s,int g){fi[cur][s]=max(fi[cur][s],g);}
    void pree(){
        int i,j,k;
        memset(pre,0,sizeof(pre));
        memset(suc,0,sizeof(suc));
        for (i=(1<<bt[m+1]);i>=0;--i){
            gi[0]=0;
            for (j=m+1;j;--j){
                k=(i>>bt[j-1])&3;
                if (k==3) break;
                if (k==2) gi[++gi[0]]=j;
                if (k==1){
                    if (!gi[0]) break;
                    suc[i][j]=gi[gi[0]];
                    pre[i][gi[gi[0]]]=j;
                    --gi[0];
                }
            }if (!j&&!gi[0]) vi[i]=true;
        }
    }
    void dp(){
        int i,j,k,s,g,p,q;
        for (i=0;i<M;++i) bt[i]=i<<1;
        cur=1;la=0;pree();
        memset(fi[cur],-60,sizeof(fi[cur]));
        inf=ans=fi[cur][0];fi[cur][0]=0;
        for (i=1;i<=n;++i){
            memset(gi,-60,sizeof(gi));
            for (j=(1<<bt[m+1])-1;j>=0;--j) gi[(j<<2)&((1<<bt[m+1])-1)]=fi[cur][j];
            for (j=(1<<bt[m+1])-1;j>=0;--j) fi[cur][j]=gi[j];
            for (j=1;j<=m;++j){
                cur^=1;la^=1;
                memset(fi[cur],-60,sizeof(fi[cur]));
                fi[cur][0]=0;
                for (k=(1<<bt[m+1])-1;k>=0;--k){
                    if (!vi[k]||fi[la][k]<=inf) continue;
                    s=k;g=fi[la][k];
                    p=(s>>bt[j-1])&ji;q=(s>>bt[j])&ji;
                    s-=(1<<bt[j-1])*p+(1<<bt[j])*q;
                    if (!p){
                        if (!q){
                            if (s) add(s,g);
                            add(s+(1<<bt[j-1])+(1<<(bt[j]+1)),g+ai[i][j]);
                        }if (q==1){
                            add(s+(1<<bt[j-1]),g+ai[i][j]);
                            add(s+(1<<bt[j]),g+ai[i][j]);
                        }if (q==2){
                            add(s+(1<<(bt[j-1]+1)),g+ai[i][j]);
                            add(s+(1<<(bt[j]+1)),g+ai[i][j]);
                        }
                    }if (p==1){
                        if (!q){
                            add(s+(1<<bt[j-1]),g+ai[i][j]);
                            add(s+(1<<bt[j]),g+ai[i][j]);
                        }if (q==1) add(s-(1<<bt[suc[k][j+1]-1]),g+ai[i][j]);
                        if (q==2){
                            if (s) continue;
                            ans=max(ans,g+ai[i][j]);
                        }
                    }if (p==2){
                        if (!q){
                            add(s+(1<<(bt[j-1]+1)),g+ai[i][j]);
                            add(s+(1<<(bt[j]+1)),g+ai[i][j]);
                        }if (q==1) add(s,g+ai[i][j]);
                        if (q==2) add(s+(1<<bt[pre[k][j]-1]),g+ai[i][j]);
                    }
                }
            }
        }
    }
    int main(){
        int i,j;scanf("%d%d",&n,&m);
        for (i=1;i<=n;++i)
            for (j=1;j<=m;++j) scanf("%d",&ai[i][j]);
        dp();printf("%d
    ",ans);
    }
    View Code

    bzoj3125 CITY

    题目大意:n*m的网格中有四种格子:不能过、左右过、上下过、能过,问一条回路走过所有非不能过的格子的方案数。

    思路:状态同上。

    注意:能更新答案的地方是最后一个非不能过的格子。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 15
    #define uu 2000000
    #define pp 50000
    #define LL long long
    using namespace std;
    int ha[2][uu],tot[2],next[uu],point[pp]={0},cur,la,nm,ai[N][N],n,m,bt[N],xx,yy;
    LL fi[2][uu];
    inline int in(){
        char ch=getchar();
        while(ch!='.'&&ch!='-'&&ch!='|'&&ch!='#') ch=getchar();
        if (ch=='.') return 1;
        if (ch=='-') return 2;
        if (ch=='|') return 3;
        return 0;}
    inline void add(int s,LL d){
        int i,x=s%pp;
        for (i=point[x];i;i=next[i])
            if (ha[cur][i]==s){fi[cur][i]+=d;return;}
        ha[cur][++nm]=s;fi[cur][nm]=d;
        next[nm]=point[x];point[x]=nm;
    }
    inline bool cg(int i,int j,int x){
        if (x==2) return ((ai[i][j]==1||ai[i][j]==2)&&(ai[i][j+1]==1||ai[i][j+1]==2));
        if (x==3) return ((ai[i][j]==1||ai[i][j]==3)&&(ai[i+1][j]==1||ai[i+1][j]==3));
    }
    void dp(){
        int i,j,k,p,q,s,ji,po,cn,cc;LL g;
        cur=1;la=0;tot[cur]=1;
        ha[cur][1]=0;fi[cur][1]=1;ji=3;
        for (i=0;i<N;++i) bt[i]=i<<1;
        for (i=1;i<=n;++i){
            for (j=tot[cur];j;--j) ha[cur][j]=(ha[cur][j]<<2)&((1<<bt[m+1])-1);
            for (j=1;j<=m;++j){
                cur^=1;la^=1;nm=0;
                memset(point,0,sizeof(point));
                for (k=tot[la];k;--k){
                    s=ha[la][k];g=fi[la][k];fi[la][k]=0;
                    if (!g) continue;
                    p=(s>>bt[j-1])&ji;
                    q=(s>>bt[j])&ji;
                    s-=(1<<bt[j-1])*p+(1<<bt[j])*q;
                    if (p==0){
                        if (q==0){
                            if (!ai[i][j]) add(s,g);
                            if (cg(i,j,3)&&cg(i,j,2)) add(s+(1<<bt[j-1])+(1<<(bt[j]+1)),g);
                        }if (q==1){
                            if (cg(i,j,2)) add(s+(1<<bt[j]),g);
                            if (cg(i,j,3)) add(s+(1<<bt[j-1]),g);
                        }if (q==2){
                            if (cg(i,j,2)) add(s+(1<<(bt[j]+1)),g);
                            if (cg(i,j,3)) add(s+(1<<(bt[j-1]+1)),g);
                        }
                    }if (p==1){
                        if (q==0){
                            if (cg(i,j,2)) add(s+(1<<bt[j]),g);
                            if (cg(i,j,3)) add(s+(1<<bt[j-1]),g);
                        }if (q==1){
                            for (cn=0,po=j+2;po<=m+1;++po){
                                cc=(s>>bt[po-1])&ji;
                                if (!cc) continue;
                                if (cc==1) ++cn;
                                if (cc==2){if (!cn) break;--cn;}
                            }add(s-(1<<bt[po-1]),g);
                        }if (q==2){
                            if (!s&&i==xx&&j==yy) add(s,g);
                        }
                    }if (p==2){
                        if (q==0){
                            if (cg(i,j,2)) add(s+(1<<(bt[j]+1)),g);
                            if (cg(i,j,3)) add(s+(1<<(bt[j-1]+1)),g);
                        }if (q==1) add(s,g);
                        if (q==2){
                            for (cn=0,po=j-1;po>0;--po){
                                cc=(s>>bt[po-1])&ji;
                                if (!cc) continue;
                                if (cc==2) ++cn;
                                if (cc==1){if (!cn) break;--cn;}
                            }add(s+(1<<bt[po-1]),g);
                        }
                    }
                }tot[cur]=nm;
            }
        }
    }
    int main(){
        int i,j;scanf("%d%d",&n,&m);
        memset(ai,0,sizeof(ai));
        for (i=1;i<=n;++i)
            for (j=1;j<=m;++j){
                ai[i][j]=in();
                if (ai[i][j]){xx=i;yy=j;}
            }
        dp();printf("%I64d
    ",fi[cur][1]);
    }
    View Code

    bzoj3814 简单回路

    题目大意:给n*m有障碍网格,q组询问,求经过(x,y)和(x+1,y)之间边的简单回路个数。

    思路:正反做两遍插头dp,对于询问就是合并从上面和从下面过来的这一行更新完之后的插头,可以暴力预处理上下能匹配成简单回路的插头对。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 1005
    #define M 20000
    #define up 4100
    #define uu 8
    #define pp 1000000007LL
    #define LL long long
    #define ji 3
    using namespace std;
    struct use{
        int x,y,p;
        bool operator<(const use&xx)const{return (x==xx.x ? y<xx.y : x<xx.x);}
    }ask[M];
    int pt=0,pa[N][2],pre[M][uu],suc[M][uu],bt[uu],ai[2][N][uu],n,m,cur,la,qq,zh[uu],
        ct[M]={0},zr[M]={0};
    LL fi[2][M],gg[M],gi[2][N][up],as[M];
    bool vi[M]={false},vv[uu];
    bool judge(int x,int y){
        int i,a,b;
        for (i=1;i<=m;++i){
            a=(((x>>bt[i-1])&ji)>0);
            b=(((y>>bt[i-1])&ji)>0);
            if (a^b) return false;
        }for (i=1;i<=m;++i)
            if ((x>>bt[i-1])&ji) break;
        memset(vv,false,sizeof(vv));
        for (;;){
            vv[i]=true;
            if (((x>>bt[i-1])&ji)==1) i=suc[x][i];
            else i=pre[x][i];
            vv[i]=true;
            if (((y>>bt[i-1])&ji)==1) i=suc[y][i];
            else i=pre[y][i];
            if (vv[i]) break;
        }for (i=1;i<=m;++i)
            if (((x>>bt[i-1])&ji)&&!vv[i]) break;
        if (i<=m) return false;
        return true;}
    int zher(int x){
        int i,y=0;
        for (i=1;i<=m;++i)
            if ((x>>bt[m-i])&ji)
                y|=(1<<bt[i-1])*(3-((x>>bt[m-i])&ji));
        return y;}
    void pree(){
        int i,j,x,zt;
        for (i=0;i<uu;++i) bt[i]=i<<1;
        for (i=(1<<bt[m+1])-1;i>=0;--i){
            for (zt=0,j=1;j<=m+1;++j){
                x=(i>>bt[j-1])&ji;
                if (x>2) break;
                if (!x) continue;++ct[i];
                if (x==1) zh[++zt]=j;
                else{
                    if (!zt) break;
                    pre[i][j]=zh[zt];
                    suc[i][zh[zt]]=j;
                    --zt;
                }
            }if (j>m+1&&!zt) vi[i]=true;
        }for (i=(1<<bt[m])-1;i;--i){
            if (!vi[i]) continue;
            zr[i]=zher(i);
            for (j=(1<<bt[m])-1;j;--j){
                if (!vi[j]) continue;
                if (ct[i]==ct[j]&&judge(i,j)){
                    pa[++pt][0]=i;pa[pt][1]=j;
                }
            }
        }
    }
    void add(int x,LL y){fi[cur][x]=(fi[cur][x]+y)%pp;}
    void dp(int kk){
        int i,j,k,s,p,q;LL g;cur=1;la=0;
        memset(fi,0,sizeof(fi));
        fi[cur][0]=1LL;
        for (i=1;i<=n;++i){
            for (j=(1<<bt[m+1])-1;j>=0;--j)
                gg[(j<<2)&((1<<bt[m+1])-1)]=fi[cur][j];
            for (j=(1<<bt[m])-1;j>=0;--j){
                if (!kk) gi[kk][i-1][j]=fi[cur][j];
                else gi[kk][n-i+1][zr[j]]=fi[cur][j];
            }for (j=(1<<bt[m+1])-1;j>=0;--j) fi[cur][j]=gg[j];
            for (j=1;j<=m;++j){
                cur^=1;la^=1;
                fi[cur][0]=1;
                for (k=(1<<bt[m+1])-1;k>=0;--k){
                    if (!vi[k]||!fi[la][k]) continue;
                    s=k;g=fi[la][k];fi[la][k]=0LL;
                    p=(k>>bt[j-1])&ji;
                    q=(k>>bt[j])&ji;
                    s-=(1<<bt[j-1])*p+(1<<bt[j])*q;
                    if (!p){
                        if (!q){
                            if (s) add(s,g);
                            if (ai[kk][i][j]&&ai[kk][i+1][j]&&ai[kk][i][j+1])
                                add(s+(1<<bt[j-1])+(1<<(bt[j]+1)),g);
                        }if (q==1){
                            if (ai[kk][i+1][j]) add(s+(1<<bt[j-1]),g);
                            if (ai[kk][i][j+1]) add(s+(1<<bt[j]),g);
                        }if (q==2){
                            if (ai[kk][i+1][j]) add(s+(1<<(bt[j-1]+1)),g);
                            if (ai[kk][i][j+1]) add(s+(1<<(bt[j]+1)),g);
                        }
                    }if (p==1){
                        if (!q){
                            if (ai[kk][i+1][j]) add(s+(1<<bt[j-1]),g);
                            if (ai[kk][i][j+1]) add(s+(1<<bt[j]),g);
                        }if (q==1) add(s-(1<<bt[suc[k][j+1]-1]),g);
                        if (q==2) continue;
                    }if (p==2){
                        if (!q){
                            if (ai[kk][i+1][j]) add(s+(1<<(bt[j-1]+1)),g);
                            if (ai[kk][i][j+1]) add(s+(1<<(bt[j]+1)),g);
                        }if (q==1) add(s,g);
                        if (q==2) add(s+(1<<bt[pre[k][j]-1]),g);
                    }
                }
            }
        }
    }
    void geta(){
        int i,j,k,qi=1;LL ans;
        for (i=1;i<n;++i)
            for (j=1;j<=m;++j)
                for(;qi<=qq&&ask[qi].x==i&&ask[qi].y==j;++qi){
                    for (ans=0LL,k=1;k<=pt;++k)
                        if ((pa[k][0]>>bt[j-1])&ji)
                            ans=(ans+gi[0][i][pa[k][0]]*gi[1][i][pa[k][1]]%pp)%pp;
                    as[ask[qi].p]=ans;
                }
    }
    int main(){
        int k,i,j,x,y;
        memset(ai,0,sizeof(ai));
        scanf("%d%d%d",&n,&m,&k);
        for (i=1;i<=n;++i)
            for (j=1;j<=m;++j) ai[0][i][j]=ai[1][i][j]=1;
        for (i=1;i<=k;++i){
            scanf("%d%d",&x,&y);
            ai[0][x][y]=ai[1][n-x+1][m-y+1]=0;
        }scanf("%d",&qq);
        for (i=1;i<=qq;++i){
            scanf("%d%d",&x,&y);
            ask[i]=(use){x,y,i};
        }sort(ask+1,ask+qq+1);
        pree();dp(0);dp(1);geta();
        for (i=1;i<=qq;++i) printf("%I64d
    ",as[i]);
    }
    View Code
  • 相关阅读:
    Mac 如何让python默认运行python3.8
    python发送post请求(转)
    Qt 学习(4)
    自定义Qt组件-通讯模块(P3)
    自定义Qt组件-通讯模块(P2)
    自定义Qt组件-通讯模块(P1)
    用 JS 做一个数独游戏(二)
    用 JS 做一个数独游戏(一)
    公交车情况数问题
    传球问题
  • 原文地址:https://www.cnblogs.com/Rivendell/p/5432911.html
Copyright © 2011-2022 走看看