2018.8.10T2(缩点,拓扑排序,最长路)

描述
小A在8102年掌握了穿越时间的科技,他想要回归遥远的2018年来看一看。

我们定义“时间线”是长度恰好为 n ,仅由 ABCD 四个大写字母组成的字符串。

设某个时间线为 S,小A可以用以下两种方式修改时间线:

交换 S 中相邻两个字符。
使用某种转移。一个转移是两个长度不超过 n的等长字符串 (Ai,Bi),可以把 S 中某个子串 Ai 替换成 Bi。
小A自然能随意行走于时间线上,但他想享受这跃迁的过程。他想考考你:初始的时间线任选,任意操作,在任意一条时间线结束,途中经过的不同时间线数量最多是多少?

注意可以经过重复的时间线,但只会计入一次答案。

输入格式
第一行两个数 n , m,表示时间线的长度和转移的个数。

后面 m 行,每行两个等长字符串 Ai,Bi,表示一个转移。

输出格式
一行,一个整数表示最大答案。

样例1
样例输入1
2 3
A B
A C
D D
样例输出1
5
样例解释1
一种最优方案:AA→AB→BA→BC→CB
限制与约定
对于 30% 的数据, n≤5, m≤5。

对于 50% 的数据, n≤10, m≤30。

对于 100% 的数据, n≤30, m≤50。

时间限制:2s

空间限制:512MB

一种很显然的暴力就是记录状态,然后根据给定的条件连边,tarjan缩点之后求最长路
常数写得好有60分
实际上有了相邻转移之后我们发现,如果A,B,C,D的个数都确定,他能通过相邻交换转移到任意状态
那我们就可以根据A,B,C,D的个数设计状态,大力算出每个点的权值再重复上述操作即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define ll long long
int n , m;
int id[31][31][31][31] , tot , tt;
int linkk[6100] , t , du[6100];
int dfn[6100] , low[6100] , cnt , cor[6100] , totc;
ll a[6100] , v[6100];
ll dp[6100];
ll jc[30];
struct node{
    int n,y,x;
}e[181000];

int read(){int sum = 0;char c = getchar();bool flag = true;while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();if(flag)  return sum;else return -sum;}  
ll calc(int A,int B,int C)
{
    int D = n - A - B - C;
    ll sum = 1;
    int a , b , c , d;a = b = c = d = 1;
    rep(i,1,n)
    {
        sum *= i;
        for(;a <= A && sum % a == 0;sum/=a,a++);
        for(;b <= B && sum % b == 0;sum/=b,b++);
        for(;c <= C && sum % c == 0;sum/=c,c++);
        for(;d <= D && sum % d == 0;sum/=d,d++);
    }
    return sum;
}
void pre(){rep(a,0,n) rep(b,0,n-a) rep(c,0,n-a-b) id[a][b][c][n-a-b-c] = ++tot,v[tot] = calc(a,b,c);return;}
char in[40];
void insert(int x,int y)
{
    e[++t].y = y;e[t].x = x;e[t].n = linkk[x];linkk[x] = t;
    return;
}
void init()
{
    rep(x,1,m)
    {
        int n1,n2,n3,n4;
        int m1,m2,m3,m4;
        n1 = n2 = n3 = n4 = m1 = m2 = m3 = m4 = 0;
        scanf("%s",in+1);
        int len = strlen(in+1);
        rep(i,1,len) 
            if(in[i] == 'A') n1++;
            else if(in[i] == 'B') n2++;
            else if(in[i] == 'C') n3++;
            else n4++;
        scanf("%s",in+1);
        len = strlen(in+1);
        rep(i,1,len)
            if(in[i] == 'A') m1++;
            else if(in[i] == 'B') m2++;
            else if(in[i] == 'C') m3++;
            else m4++;
        m1=n1-m1;m2=n2-m2;m3=n3-m3;m4=n4-m4;
        rep(a,n1,n) rep(b,n2,n-a) rep(c,n3,n-a-b)
        {
            int d = n - a - b - c;
            if(d < n4) continue;
            insert(id[a][b][c][d],id[a-m1][b-m2][c-m3][d-m4]);
            tt++;
        }
    }
    return;
}
stack<int>st;
bool f[6100];
void tarjan(int x)
{
    dfn[x] = low[x] = ++cnt;
    f[x] = true;st.push(x);
    for(int i = linkk[x];i;i = e[i].n)
    {
        int y = e[i].y;
        if(!dfn[y])
        {
            tarjan(y);
            low[x] = min(low[x] , low[y]);
        }
        else 
            if(f[y]) low[x] = min(low[x] , dfn[y]);
    }
    if(low[x] == dfn[x])
    {
        ll k = v[x];
        cor[x] = ++totc;f[x] = false;
        while(st.top() != x)
            cor[st.top()] = totc,
            f[st.top()] = false,k += v[st.top()],
            st.pop();
        st.pop();a[totc] = k;
    }
    return;
}
void sd()
{
    memset(linkk,0,sizeof(linkk));t = 0;
    rep(i,1,tt)
    {
        int x = e[i].x , y = e[i].y;
        if(cor[x] != cor[y]) 
            insert(cor[x] , cor[y]) , du[cor[y]]++;
    }
    return;
}
queue<int>q;
ll ans = 0;
void topsort()
{
    rep(i,1,tot) if(!du[i]) q.push(i);
    while(!q.empty())
    {
        int x = q.front();
        dp[x] += a[x];
        ans = max(ans,dp[x]);
        for(int i = linkk[x];i;i = e[i].n)
        {
            int y = e[i].y;
            du[y]--;
            dp[y] = max(dp[y] , dp[x]);
            if(!du[y]) q.push(y);
        }
        q.pop();
    }
    return;
}
int main()
{
    n = read();m = read();
    pre();
    init();rep(i,1,tot)if(!dfn[i])tarjan(i);sd();
    topsort();
    printf("%lld\n",ans);
    return 0;
} 
    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/a1035719430/article/details/81710145
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞