• 《洛谷P2704 [NOI2001]炮兵阵地》


    非常细细细的一题。

    首先,这数据量显然是状压。

    dp[i][j][k] 表示 到第i行,第i行状态为j,第i - 1行状态未k的最大方案数。

    我们从上向下考虑的话,每个放置的棋子会被上面两行棋子的放置状态所影响。

    所以我们每次转移的时候需要枚举上面的两行。

    这样的话复杂度就是 n * m * m * m。

    这显然已经超了(但是正解还就是这样)。

    考虑后可以发现,很多状态都是会冲突被删掉的,这样复杂度就少了非常多,所以就够了。

    所以我们可以先预处理出冲突的状态。

    这里的判断很巧妙,首先把每一行的原图转换成二进制数,去判断山地有没有防炮台。

    所以显然我们去把山地转成1,然后就可以位运算判断。

    然后对于左右的判断也可以位运算来加速。

    空间不够必须用滚动数组。

    debug调到裂开。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 5005;
    const int M = 1e5 + 5;
    const LL Mod = 10007;
    #define pi acos(-1)
    #define INF 1e9 + 5
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline LL read(){
            LL x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    int n,m,a[105];
    int dp[3][1 << 10][1 << 10],num[1 << 10];
    bool isvis[105][1 << 10];
    int cal(int state)
    {
        int num = 0;
        for(int j = 0;j < m;++j) num += ((state >> j) & 1);
        return num;
    }
    int main()
    {
        n = read(),m = read();
        for(int i = 0;i < n;++i)
        {
            string s;cin >> s;
            for(int j = 0;j < s.size();++j) a[i] += (s[j] == 'H' ? (1 << j) : 0);
        }    
        for(int i = 0;i < (1 << m);++i) num[i] = cal(i);
        for(int i = 0;i < n;++i)
            for(int j = 0;j < (1 << m);++j)
            {
                if((j & a[i]) || (j & (j << 1)) || (j & (j << 2)) || (j & (j >> 1) || (j & (j >> 2)))) isvis[i][j] = 0;
                else isvis[i][j] = 1;
            }
        for(int i = 0;i < (1 << m);++i)
        {
            if(!isvis[0][i]) continue;
            int ma = num[i];
            dp[0][i][0] = ma;
            for(int j = 0;j < (1 << m);++j)
            {
                if(!isvis[1][j] || (i & j)) continue;
                int ta = ma + num[j];
                dp[1][j][i] = ta;
            }
        }
        for(int i = 2;i < n;++i)//line
        {
            for(int s1 = 0;s1 < (1 << m);++s1)
            {
                if(!isvis[i - 2][s1]) continue;
                for(int s2 = 0;s2 < (1 << m);++s2)
                {
                    if(!isvis[i - 1][s2] || ((s1 & s2) == 1)) continue;
                    for(int s3 = 0;s3 < (1 << m);++s3)
                    {
                        if(!isvis[i][s3]) continue;
                        if((s1 & s3) || (s2 & s3)) continue;
                        dp[i % 3][s3][s2] = max(dp[i % 3][s3][s2],dp[(i - 1) % 3][s2][s1] + num[s3]);
                    }
                }
            }
        }
        int ans = 0;
        for(int i = 0;i < (1 << m);++i)
            for(int j = 0;j < (1 << m);++j) ans = max(ans,dp[(n - 1) % 3][i][j]);
        printf("%d
    ",ans);
        system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    We Never Told Him He Couldn't Do It
    我是天蝎
    学习生活,有感动的时候
    .NET中AOP方便之神SheepAspect
    Effective Java (类和接口)
    Step By Step(Java 系列的目录)
    Linux Shel高级技巧(目录)
    Linux Shell经典实例解析Oracle启动脚本(下)
    Java和C++在细节上的差异(目录)
    Linux Shell经典实例解析Oracle启动脚本(上)
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/14163250.html
Copyright © 2020-2023  润新知