• [usaco6.1.1Postal Vans]


    来自FallDream的博客,未经允许,请勿转载,谢谢。


    给你一个4*n的棋盘,问从(1,1)出发恰好经过所有格子一次的走法数量.(n<=1000)

    插头dp,用f[i][j][k]表示转移到第i行第j列,插头的状态是k的方案数,套上高精度。

    假设要转移到格子(i,j) 前一个格子的右插头是p,上一个格子的下插头是q,

    p和q都没有插头时,现在这个格子显然只能有向右和向下的插头,插头状态变成()

    p和q只有一个有插头时,一个插头只能与这个插头对接,另一个插头可右可下,分别转移

    pq都有插头的时候,显然只能和这两个插头对接,考虑维护联通性。

    如果两个插头是(),那么会形成一个环,只有在最后一个格子才能转移。

    如果两个插头是((或者)),这两个联通块被合并,把这两个插头去掉,然后把他们匹配的两个相同的插头改成()即可。

    如果这两个插头是)(,那么直接去掉这两个插头即可。

    插头的状态可以与处理,总共只有21种,复杂度O(4*n*21*高精度)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<iomanip>
    #define MN 2200
    #define mod 1000000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    struct Hpc
    {
        int  len,s[100];
        void init(int x){memset(s,0,sizeof(int)*(len+1));s[1]=x;len=(x>0);}
        void operator += (Hpc y)
        {
            len=max(len,y.len)+1;
            for(int i=1;i<=len;++i)
            {
                s[i]+=y.s[i];
                if(s[i]>=mod)
                {
                    s[i+1]+=s[i]/mod;
                    s[i]%=mod;
                }
            }
            if(!s[len]) --len;
        }
        void print()
        {
            printf("%d",s[len]);
            for(int i=len-1;i>0;--i)
                cout<<setw(9)<<setfill('0')<<s[i];
        }
    }f[5][1<<12],ans;
    int n,tot=0,s[MN+5],c[MN+5][8],q[8],top;
    
    int main()
    {
        n=read();f[4][0].init(1);
        for(int i=0;i<1<<(4<<1)+2;++i)
        {
            s[++tot]=i;top=0;
            for(int j=0;j<=4;++j)
            {
                int x=i>>(j<<1);
                if((x&3)==3) {top=-1;break;}
                if((x&3)==1) q[++top]=j;
                if((x&3)==2)
                {
                    if(!top) {top=-1;break;}
                    else c[tot][q[top]]=j,c[tot][j]=q[top],--top;
                }
            }
            if(top) --tot;
        }
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=tot;++j)
            {
                if(s[j]&3) f[0][s[j]].init(0);
                else f[0][s[j]]=f[4][s[j]>>2];
            }
            for(int j=1;j<=4;++j)
            {
                int x=(j-1)<<1;
                memset(f[j],0,sizeof(f[j]));
                for(int k=1;k<=tot;++k)
                {
                    
                    int p=(s[k]>>x)&3;
                    int q=(s[k]>>(x+2))&3;
                    if(!p&&!q)  f[j][s[k]|(9<<x)]+=f[j-1][s[k]];
                    else if(p&&q)
                    {
                        if(p==1&&q==2)
                        {
                            if(i==n&&j==4&&s[k]==(9<<x)) ans+=f[j-1][s[k]];
                        }
                        else if(p==1&&q==1)
                            f[j][s[k]^(5<<x)^(3<<(c[k][j]<<1))]+=f[j-1][s[k]];
                        else if(p==2&&q==1) f[j][s[k]^(6<<x)]+=f[j-1][s[k]];
                        else if(p==2&&q==2) f[j][s[k]^(10<<x)^(3<<(c[k][j-1]<<1))]+=f[j-1][s[k]];
                    
                    }
                    else
                    {
                        f[j][s[k]]+=f[j-1][s[k]];
                        f[j][(s[k]^(p<<x)^(q<<x+2))|(p<<x+2)|(q<<x)]+=f[j-1][s[k]];
                    }
                }
            }
        }
        ans+=ans;ans.print();
        return 0;
    }
  • 相关阅读:
    1.1【基本路由原理】(二层转发原理)1
    NP课前资料2-IOU的传统安装方式
    NP课前资料1-安装GNS3桥接ASA
    1.2 数据仓库的特性
    1-1 事务型处理与分析型处理
    易用性测试关注点(转)
    Jenkins+svn+ant+tomcat持续集成
    并发数计算
    性能测试需求采集
    性能测试指标分析与监控
  • 原文地址:https://www.cnblogs.com/FallDream/p/usacoPostalVans.html
Copyright © 2020-2023  润新知