LOJ 10172 涂抹果酱

题目链接:https://loj.ac/problem/10172

思路:

看到数据范围,考虑状压$dp$。

发现每一格有$3$种情况,考虑用三进制来表示。

枚举所有情况,将可行解与其三进制建立映射关系。

由于第$k$行上下互不影响,我们可以分别进行$dp$,根据乘法原理相乘即可得到答案。

为了优化时间,我们可以先将可互相转移的状态记录下来,$dp$时直接查询即可。

代码:

#include <bits/stdc++.h>
const int MAXM = 10050;
const int p = 1000000;
typedef int intt;
#define int long long
using namespace std;
vector<int> pb;
map<int, string> mp;
bool c[1050][1050];
int n, m, k, num, ans1, ans2, res, x[MAXM], f[MAXM][50], g[MAXM][50];
void init(int x) {
    int p = 1, xx = x;
    string s;
    s.clear(); 
    do{
        s += (x % 3 + '0');
    } while(x /= 3);
    while(s.length() != m)
        s += '0';
    reverse(s.begin(), s.end());
    for(int i = 1; i < (int)s.length(); i++) {
        if(s[i] == s[i - 1])
            return ;
    }
    pb.push_back(xx);
    mp[xx] = s;
    //cout << xx << " " << mp[xx] << endl;
}
bool check(int x, int y) {
    string s, t;
    s = mp[pb[x]];
    t = mp[pb[y]];
    for(int i = 0; i < m; i++) {
        if(s[i] == t[i])
            return false;
    }
    return true;
}
intt main() {
    cin >> n >> m >> k;
    x[0] = -1;
    for(int i = 1; i <= m; i++) {
        cin >> x[i];
        if(x[i] == x[i - 1]) {
            cout << "0" << endl;
            return 0;
        }
        res = res * 3 + (x[i] - 1);
    }
    for(int i = 0; i < (int)pow(3, m); i++) {
        if(res == i)
            num = (int)pb.size();
        init(i);
    }
//    cout << a[k] << endl << mp[pb[num]] << endl;
    for(int j = 0; j < (int)pb.size(); j++) {
        for(int l = 0; l < (int)pb.size(); l++) {
            c[j][l] = check(j, l);
        }
    }
    f[k][num] = 1;
    for(int i = k - 1; i >= 1; i--) {
        for(int j = 0; j < (int)pb.size(); j++) {
            for(int l = 0; l < (int)pb.size(); l++) {
                if(c[j][l])
                    f[i][j] = (f[i][j] + f[i + 1][l]) % p;
            }
        }
    }
    g[k][num] = 1;
    for(int i = k + 1; i <= n; i++) {
        for(int j = 0; j < (int)pb.size(); j++) {
            for(int l = 0; l < (int)pb.size(); l++) {
                if(c[j][l])
                    g[i][j] = (g[i][j] + g[i - 1][l]) % p;
            }
        }
    }
    for(int i = 0; i < (int)pb.size(); i++) {
        ans1 = (ans1 + f[1][i]) % p;
        ans2 = (ans2 + g[n][i]) % p;
    }
    cout << (1ll * ans1 * ans2) % p << endl;
    return 0;
}

 

posted @ 2019-10-23 21:48  BeyondLimits  阅读(184)  评论(0编辑  收藏  举报