#35 string(缩点+动态规划)

  容易发现有了交换相邻字符的操作后,只要字符串所含有的字符种类和数量相同其就是等价的。这样的状态只有n^3级别,将其抽象成点子串变换抽象成边后就是求最长路径了,缩点dp解决。

  码量巨大,不是很明白要怎样才能用3k写完。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int read()
{
    int 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;
}
#define N 55
#define P 100000000000000000LL
unsigned long long C[N][N];
int n,m,p[N*N*N],t=0,tmp[20];
int dfn[N*N*N],low[N*N*N],stk[N*N*N],SET[N*N*N],top=0,cnt=0;
bool flag[N*N*N];
char s[N],s2[N];
vector<int> ele[N*N*N];
struct magic{int n,a,b,c,x,y,z;}a[N<<1];
struct data{int to,nxt;}edge[N*N*N*N];
struct biginteger
{
    unsigned long long x,y;
    bool operator <(const biginteger&a) const
    {
        return x==a.x?y<a.y:x<a.x;
    }
    bool operator >(const biginteger&a) const
    {
        return x==a.x?y>a.y:x>a.x;
    }
    biginteger operator +(const biginteger&a) const
    {
        biginteger v=(biginteger){x,y};
        v.x+=a.x;v.y+=a.y;
        if (v.y>=P) v.x++,v.y-=P;
        return v;
    }
    biginteger operator *(const unsigned long long&a) const
    {
        unsigned long long v[40]={0};int n=0;
        biginteger tmp=(biginteger){x,y};
        while (tmp.y) v[++n]=tmp.y%10,tmp.y/=10;    
        if (tmp.x)
        {
            n=17;
            while (tmp.x) v[++n]=tmp.x%10,tmp.x/=10;
        }
        for (int i=1;i<=n;i++) v[i]=v[i]*a;
        for (int i=1;i<=n;i++)
        v[i+1]+=v[i]/10,v[i]%=10;
        while (v[n+1]) n++,v[n+1]+=v[n]/10,v[n]%=10;
        for (int i=17;i>=1;i--) tmp.y=tmp.y*10+v[i];
        for (int i=n;i>=18;i--) tmp.x=tmp.x*10+v[i];
        return tmp;
    }
}value[N*N*N],V[N*N*N],f[N*N*N];
int trans(int x,int y,int z){return x*(n+1)*(n+1)+y*(n+1)+z+1;}
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void tarjan(int k)
{
    dfn[k]=low[k]=++cnt;
    flag[k]=1;stk[++top]=k;
    for (int i=p[k];i;i=edge[i].nxt)
    if (!dfn[edge[i].to]) tarjan(edge[i].to),low[k]=min(low[k],low[edge[i].to]);
    else if (flag[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]);
    if (dfn[k]==low[k])
    {
        t++;
        while (stk[top]!=k)
        {
            SET[stk[top]]=t;
            ele[t].push_back(stk[top]);
            V[t]=V[t]+value[stk[top]];
            flag[stk[top]]=0;
            top--;
        }
        SET[k]=t;ele[t].push_back(k);V[t]=V[t]+value[k];flag[k]=0;top--;
    }
}
namespace newgraph
{
    int n,t=0,p[N*N*N]={0},degree[N*N*N],q[N*N*N];
    struct data{int to,nxt;}edge[N*N*N*N];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void topsort()
    {
        int head=0,tail=0;for (int i=1;i<=n;i++) if (!degree[i]) q[++tail]=i;
        while (tail<n)
        {
            int x=q[++head];
            for (int i=p[x];i;i=edge[i].nxt)
            {
                degree[edge[i].to]--;
                if (!degree[edge[i].to]) q[++tail]=edge[i].to;
            }
        }
    }
    void solve()
    {
        topsort();
        for (int i=n;i>=1;i--)
        {
            for (int j=p[q[i]];j;j=edge[j].nxt)
            f[q[i]]=max(f[q[i]],f[edge[j].to]);
            f[q[i]]=f[q[i]]+V[q[i]];
        }
    }
}
void rebuild()
{
    memset(flag,0,sizeof(flag));
    for (int i=1;i<=t;i++)
    {
        for (int j=0;j<ele[i].size();j++)
            for (int k=p[ele[i][j]];k;k=edge[k].nxt)
            if (!flag[edge[k].to]&&SET[edge[k].to]!=i)
            {
                flag[edge[k].to]=1;
                newgraph::addedge(i,SET[edge[k].to]);
                newgraph::degree[SET[edge[k].to]]++;
            }
        for (int j=0;j<ele[i].size();j++)
            for (int k=p[ele[i][j]];k;k=edge[k].nxt)
            flag[edge[k].to]=0;
    }
    newgraph::n=t;
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=m;i++)
    {
        scanf("%s",s+1);scanf("%s",s2+1);
        a[i].n=strlen(s+1);
        for (int j=1;j<=a[i].n;j++)
        if (s[j]=='A') a[i].a++;
        else if (s[j]=='B') a[i].b++;
        else if (s[j]=='C') a[i].c++;
        for (int j=1;j<=a[i].n;j++)
        if (s2[j]=='A') a[i].x++;
        else if (s2[j]=='B') a[i].y++;
        else if (s2[j]=='C') a[i].z++;
        if (a[i].a==a[i].x&&a[i].b==a[i].y&&a[i].c==a[i].z) a[i].a=a[i].b=a[i].c=n+1;
    }
    C[0][0]=1;
    for (int i=1;i<=n;i++)
    {
        C[i][0]=C[i][i]=1;
        for (int j=1;j<i;j++)
        C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
    for (int i=0;i<=n;i++)
        for (int j=0;j<=n-i;j++)
            for (int k=0;k<=n-i-j;k++)
            {
                value[trans(i,j,k)]=(biginteger){0,C[n][i]};
                value[trans(i,j,k)]=value[trans(i,j,k)]*C[n-i][j];
                value[trans(i,j,k)]=value[trans(i,j,k)]*C[n-i-j][k];
                for (int x=1;x<=m;x++)
                if (i>=a[x].a&&j>=a[x].b&&k>=a[x].c&&n-i-j-k>=a[x].n-a[x].a-a[x].b-a[x].c)
                addedge(trans(i,j,k),trans(i-a[x].a+a[x].x,j-a[x].b+a[x].y,k-a[x].c+a[x].z));
            }
    t=0;
    for (int i=0;i<=n;i++)
        for (int j=0;j<=n-i;j++)
            for (int k=0;k<=n-i-j;k++)
            if (!dfn[trans(i,j,k)]) tarjan(trans(i,j,k));
    rebuild();
    newgraph::solve();
    biginteger ans=(biginteger){0,0};
    for (int i=1;i<=t;i++) ans=max(ans,f[i]);
    if (ans.x)
    {
        cout<<ans.x;
        int x=0;
        while (ans.y) tmp[++x]=ans.y%10,ans.y/=10;
        for (int i=17;i>=1;i--) cout<<tmp[i];
    }
    else cout<<ans.y;
    return 0;
}

 

转载于:https://www.cnblogs.com/Gloid/p/9613467.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值