容易发现有了交换相邻字符的操作后,只要字符串所含有的字符种类和数量相同其就是等价的。这样的状态只有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; }