【XSY1285】【BZOJ3814】【清华集训2014】简单回路 状压DP

来源:互联网 发布:pc网络电视直播软件 编辑:程序博客网 时间:2024/05/16 11:30

题目描述

  给你一个n×m的网格图和k个障碍,有q个询问,每次问你有多少个不同的不经过任何一个障碍点且经过(x,y)(x+1,y)之间的简单回路

  n1000,m6,q10000

题解

  简单插头DP

  先用DP求出前面i行的的方案数和后面i行的方案数,询问时暴力合并。

  其实状态数很少的(不到200

  时间复杂度:O(???)

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;ll p=1000000007;int c[100010];int d[1010];int ld[1010][10];int rd[1010][10];int cnt;int n,m,k,q;int la[10];int ra[10];int set(int s,int x,int v){    s&=~(3<<(2*(x-1)));    s|=v<<(2*(x-1));    return s;}int get(int s,int x){    return (s>>(2*(x-1)))&3;}int st[10];void dfs(int x,int s){    if(x>m+1)    {        int i;        int now=0;        for(i=1;i<=m+1;i++)        {            if(get(s,i)==1)                st[++now]=i;            else if(get(s,i)==2)            {                la[i]=st[now];                ra[st[now]]=i;                now--;            }            if(now<0)                return;        }        if(now>0)            return;        for(i=1;i<=m+1;i++)            fprintf(stderr,"%d",get(s,i));        fprintf(stderr,"\n");        d[++cnt]=s;        c[s]=cnt;        memcpy(ld[cnt],la,sizeof la);        memcpy(rd[cnt],ra,sizeof ra);        return;    }    int i;    for(i=0;i<=2;i++)        dfs(x+1,set(s,x,i));}void add(ll &x,ll y){    x=(x+y)%p;}struct dp{    int a[1010][10];    ll f[1010][10][200];    void solve()    {        f[1][1][1]=1;        int i,j,k;        for(i=1;i<=n;i++)        {            for(j=1;j<=m;j++)                for(k=1;k<=cnt;k++)                {                    if(!f[i][j][k])                        continue;                    int s=d[k];                    int l=get(s,j);                    int r=get(s,j+1);                    if(a[i][j])                    {                        if(!l&&!r)                            add(f[i][j+1][k],f[i][j][k]);                        continue;                    }                    if(!l)                        if(!r)                        {                            add(f[i][j+1][k],f[i][j][k]);                            int v=set(s,j,1);                            v=set(v,j+1,2);                            add(f[i][j+1][c[v]],f[i][j][k]);                        }                        else if(r==1)                        {                            add(f[i][j+1][k],f[i][j][k]);                            int v=set(s,j,1);                            v=set(v,j+1,0);                            add(f[i][j+1][c[v]],f[i][j][k]);                        }                        else                        {                            add(f[i][j+1][k],f[i][j][k]);                            int v=set(s,j,2);                            v=set(v,j+1,0);                            add(f[i][j+1][c[v]],f[i][j][k]);                        }                    else if(l==1)                    {                        if(!r)                        {                            add(f[i][j+1][k],f[i][j][k]);                            int v=set(s,j,0);                            v=set(v,j+1,1);                            add(f[i][j+1][c[v]],f[i][j][k]);                        }                        else if(r==1)                        {                            int v=set(s,j,0);                            v=set(v,j+1,0);                            v=set(v,rd[k][j+1],1);                            add(f[i][j+1][c[v]],f[i][j][k]);                        }                        else                        {//                          fprintf(stderr,"orzzjt\n");                        }                    }                    else                    {                        if(!r)                        {                            add(f[i][j+1][k],f[i][j][k]);                            int v=set(s,j,0);                            v=set(v,j+1,2);                            add(f[i][j+1][c[v]],f[i][j][k]);                        }                        else if(r==1)                        {                            int v=set(s,j,0);                            v=set(v,j+1,0);                            add(f[i][j+1][c[v]],f[i][j][k]);                        }                        else                        {                            int v=set(s,j,0);                            v=set(v,j+1,0);                            v=set(v,ld[k][j],2);                            add(f[i][j+1][c[v]],f[i][j][k]);                        }                    }                }            for(j=1;j<=cnt;j++)                if(!get(d[j],m+1))                    add(f[i+1][1][c[d[j]<<2]],f[i][m+1][j]);        }    }};dp a,b;int tot;int e1[10];int e2[10];int op[1010];int f[1010];struct list{    int h[210];    int v[100010];    int t[100010];    int n;    list()    {        n=0;        memset(h,0,sizeof h);;    }    void add(int x,int y)    {        n++;        v[n]=y;        t[n]=h[x];        h[x]=n;    }};list e;int find(int x){    return f[x]==x?x:f[x]=find(f[x]);}int check(int x,int y){    if(x==53&&y==53)        int xxx=1;    int i;    for(i=1;i<=m+1;i++)    {        bool x1=get(d[x],i);        bool y1=get(d[y],i);        if(x1^y1)            return 0;    }    for(i=1;i<=m+1;i++)        f[i]=i;    int fa;    for(i=1;i<=m+1;i++)        if(get(d[x],i))        {            fa=find(i);            if(get(d[x],i)==1)                f[find(i)]=find(rd[x][i]);            if(get(d[y],i)==1)                f[find(i)]=find(rd[y][i]);        }    for(i=1;i<=m+1;i++)        if(get(d[x],i)&&find(i)!=fa)            return 0;    return 1;}int main(){    freopen("d2t1.in","r",stdin);    freopen("d2t1.out","w",stdout);    scanf("%d%d%d",&n,&m,&k);    int j,l;    int i,x,y;    for(i=1;i<=k;i++)    {        scanf("%d%d",&x,&y);        a.a[x][y]=b.a[n-x+1][y]=1;    }    dfs(1,0);    for(i=1;i<=cnt;i++)        for(j=1;j<=cnt;j++)            if(check(i,j))                e.add(i,j);    a.solve();    b.solve();    scanf("%d",&q);    for(i=1;i<=q;i++)    {        scanf("%d%d",&x,&y);        ll ans=0;        for(j=1;j<=cnt;j++)        {            int s=d[j];            if(get(s,m+1))                continue;            if(!get(s,y))                continue;            int bo=1;            tot=0;            for(l=1;l<=m;l++)                if(get(s,l))                {                    if((a.a[x][l]||a.a[x+1][l]))                    {                        bo=0;                        break;                    }                    tot++;                    e1[tot]=l;                    e2[tot]=get(s,l);                }            if(!bo)                continue;            for(l=e.h[j];l;l=e.t[l])                ans=(ans+a.f[x+1][1][c[s<<2]]*b.f[n-x+1][1][c[d[e.v[l]]<<2]])%p;        }        printf("%lld\n",ans);    }    return 0;}