zoukankan      html  css  js  c++  java
  • GYM102219F Military Class(状压DP)

    题意:

    给两个 1 - n的序列,要求序列中的数两两配对,使得配对的两个数绝对值之差小于 e ,并且还有 k 对限制,即 u 不能和 v 配对。

    题解:

    状压DP,

    就是在N的值比较小的时候,可以用一个整数表示一行的DP状态,这个数的二进制反映了这一行的情况。

    比如状态F(i, j)

    假设第二维DP状态J的二进制形式是10001001,那么1就表示当前位置被访问,0就表示当前位置未访问。

    因此,我们需要一些二进制操作来维护DP数组:

    x>>1;//去掉末位数
    x<<1;//在末尾增加一个0
    x<<1|1;//在末尾增加一个1
    x|1;//将末尾数置为1
    x|1-1;//将末尾数置为0
    x^1;//将末尾数取反
    x|(1<<(i-1));//将从右往左第i个数变成1
    x&~(1<<(i-1));//将从右往左第i个数变成0
    x^(1<<(i-1));//将从右往左第i个数取反
    x&(1<<i-1);//取后i位
    x|(1<<i-1);//将后面i位变成1
    x^(1<<i-1);//将后面i位取反
    x|(x+1);//将末尾最后一个0变成1

    观察到e的值也只有4,所以可以用状压表示配对到当前数时,已经用了9个数中的哪几个。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2005;
    const int mod=1e9+7;
    typedef long long ll;
    ll f[maxn][maxn],g[maxn][maxn],ans;
    int n,e,k;
    int main () {
        scanf("%d%d%d",&n,&e,&k);
        for (int i=0;i<k;i++) {
            int x,y;
            scanf("%d%d",&x,&y);
            g[x][y]=1;
        }
        f[0][0]=1;
        for (int i=1;i<=n;i++) 
            for (int x=0;x<(1<<2*e+1);x++)
                for (int j=-e;j<=e;j++) {
                    int k=i+j;
                    if (k<1||k>n||g[i][k]) continue;
                    if ((x>>1)&(1<<(j+e))) continue;
                    f[i][(x>>1)|(1<<(j+e))]=f[i][(x>>1)|(1<<(j+e))]+f[i-1][x];
                    f[i][(x>>1)|(1<<(j+e))]%=mod;
                }
        for (int i=0;i<(1<<2*e+1);i++) ans+=f[n][i],ans%=mod;
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    LM算法学习笔记(一)
    USB3.0剖析(锆石科技FPGA)
    USB2.0系列(锆石科技FPGA)
    异步FIFO
    总线时钟同步
    [已解决]Mac下Anaconda-Navigator闪退问题
    [已解决]Mac下运行spyder提示"Python 意外退出"
    博客园账号被盗
    unhandled event loop exception解决方案
    初识ListView
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13764663.html
Copyright © 2011-2022 走看看