状压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\n",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\n",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\n",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\n",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\n",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\n",as[i]);
}
View Code

 

posted @ 2016-04-25 21:55  Rivendell  阅读(1271)  评论(0编辑  收藏  举报