#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; }