CodeForces 781D Axel and Marston in Bitland DP

题意:

有一个\(n\)个点\(m\)条边的无向图,边有两种类型,分别用\(0\)\(1\)标识
因此图中的任意一条路径都对应一个\(01\)字符串
定义一个无限长的字符串\(s\)
开始令\(s'=0\),然后将\(s'\)的反串\(\bar{s'}\)拼到后面得到\(s' \bar{s'}\),如此反复最终得到\(s\)
求从起点出发,在串\(s\)上走最多能走多少步

分析:

\(arrive(i,t,u)\)表示从点\(u\)出发一共走了\(2^i\)步所能到达的点的集合,其中\(t=0\)表示在\(s\)上走,\(t=1\)表示在串\(\bar{s}\)上走
假设在\(s\)上有个\(u \to v\)长为\(2^i\)的路径,在\(\bar s\)上有个\(v \to w\)长为\(2^i\)的路径,那么拼起来在\(s\)上就有一条\(u \to w\)长为\(2^{i+1}\)的路径
所以\(arrive(i+1,t,u)=\bigcup\limits_{v \in arrive(i,t,u)} arrive(i,1-t,v)\)

再令\(go(i, t, u)\)表示第\(i\)轮迭代后,从点\(u\)出发在串\(s\)\(\bar s\)上最多走多少步
如果\(v \in arrive(i,t,u)\),那么就可以用\(2^i + arrive(i,1-t,v)\)去更新\(go(i+1,t,u)\),相当于把两段路拼起来

#include <cstdio>
#include <bitset>
using namespace std;

const int maxn = 500;
const int maxlog = 61;
typedef long long LL;

LL go[maxlog][2][maxn];
bitset<maxn> arrive[maxlog][2][maxn];

void max(LL& a, LL b) { if(b > a) a = b; }

int main()
{
    int n, m; scanf("%d%d", &n, &m);
    while(m--) {
        int u, v, t; scanf("%d%d%d", &u, &v, &t);
        u--; v--;
        go[0][t][u] = 1;
        arrive[0][t][u][v] = 1;
    }

    for(int i = 0; i + 1 < maxlog; i++) {
        for(int t = 0; t < 2; t++) {
            for(int u = 0; u < n; u++) {
                go[i+1][t][u] = go[i][t][u];
                for(int v = 0; v < n; v++) if(arrive[i][t][u][v]) {
                    arrive[i+1][t][u] |= arrive[i][t^1][v];
                    max(go[i+1][t][u], (1LL << i) + go[i][t^1][v]);
                }
            }
        }
    }

    const LL limit = 1000000000000000000LL;
    LL& ans = go[maxlog - 1][0][0];
    if(ans > limit) puts("-1");
    else printf("%lld\n", ans);

    return 0;
}
posted @ 2017-03-06 20:53  AOQNRMGYXLMV  阅读(...)  评论(... 编辑 收藏