题解:12.14 模拟赛解题报告 神秘大矢
后话:这已经不是写过最长的代码了。
纪念历史性时刻
Description
你是游戏设计师,你要设计所有长度为K的字符串,每个字符是 A 或 B 或 C 或 D,显然共有\(4^K\)个不同的字符串,你要给每个字符串都分配一种颜色,不同的字符串可以分配相同的颜色,颜色分配过程是由你来决定的。
奶牛Bessie是这个游戏的玩家,首先Bessie会输入一个长度是K的字符串S(每个字符也是A 或 B 或 C 或 D),然后Bessie每一步操作是如下两种选择之一:
1、 交换当前字符串\(S\)的相邻的两个字符。注意,第一个字符和最后一个字符不算相邻,即\(S\)不能看成一个环。
2、如果当前字符串\(S\)含有子串\(b[i]\),那么可以把该子串替换成字符串\(c[i]\)。其中\(b\)数组和\(c\)数组都是字符串数组,作为输入数据给出来的。
如果Bessie能够通过上面的操作,使得从字符串S出发,通过若干次操作之后,能够变成字符串\(T\)(\(T\)和\(S\)是不同的字符串),且字符串\(T\)和字符串\(S\)是相同颜色的,那么Bessie就会胜利了。
作为游戏设计师的你,你的目的是想让Bessie永远都不可能胜利,也就是说无论Bessie输入的字符串\(S\)是什么,都不可能胜利。
显然,这与你对\(4^K\)个不同的字符串如何分配颜色是非常重要的。现在的问题是,你至少需要多少种不同的颜色,才能使得Bessie永远不可能胜利。
Analysis
先考虑将多个状态压缩成\([a_1\space a_2\space a_3\space a_4]\),表示\(a_1\)个A,\(a_2\)个B,\(a_3\)个C,\(a_4\)个D组成的字符串,显然,这样会使状态数大大减少,空间复杂度降为 \(O(n^3)\)。
其次考虑,如果状态\(A\)可以通过若干次操作得到状态\(B\),则称它们是联通的。通过对可以一步达到的状态连接边,对它们进行缩点。
观察到,一个联通块的贡献取决于块中最长路径长度。路径的长度定义为路径上的点权之和,而点权指一个状态中的可能字符串数量。
如何计算可能字符串数量呢?观察到\(30!\)达到了惊人的\(10^{32}\)以上,所以方案一即\(\frac{K!}{a_1!a_2!a_3!a_4!}\)作废。然而还可采用另一种方法,即 \(\binom{K}{a_1}\binom{K-a_1}{a_2}\binom{K-a_1-a_2}{a_3}\),预处理一下杨辉三角即可轻松算出。
最后,拓扑dp处理最长路径长度。代码总长度4k,非常令人难评,暂时是写过最长的代码。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=55,M=55*55*55;
LL G,K,n;
string B,C;
int cnt;
int id[N][N][N][N];
LL siz[M];
LL qkpow(LL x,LL y){
LL res=1;
while(y){
if(y&1)res=res*x;
x=x*x;
y>>=1;
}
return res;
}
struct Node{
int a[4];
}idv[M];
LL f[55][55];
int cf[N];
LL cal(Node x){
LL tot=f[K][x.a[0]];
tot*=f[K-x.a[0]][x.a[1]];
tot*=f[K-x.a[0]-x.a[1]][x.a[2]];
return tot;
}
struct Lim{
int b[4];
int c[4];
}A[N];
int gt(Node x){
return id[x.a[0]][x.a[1]][x.a[2]][x.a[3]];
}
bool operator == (Lim x,Lim y){
for(int i=0;i<4;i++)
if(x.b[i]!=y.b[i])
return false;
for(int i=0;i<4;i++)
if(x.c[i]!=y.c[i])
return false;
return true;
}
bool operator >= (Node x,Node y){
for(int i=0;i<4;i++)
if(x.a[i]<y.a[i])
return false;
return true;
}
Node operator - (Node x,Node y){
Node ans=x;
for(int i=0;i<4;i++)
ans.a[i]-=y.a[i];
return ans;
}
Node operator + (Node x,Node y){
Node ans=x;
for(int i=0;i<4;i++)
ans.a[i]+=y.a[i];
return ans;
}
bool cmp(Lim x,Lim y){
for(int i=0;i<4;i++){
if(x.b[i]!=y.b[i])
return x.b[i]<y.b[i];
}
for(int i=0;i<4;i++){
if(x.c[i]!=y.c[i])
return x.c[i]<y.c[i];
}
}
Node inp(int a,int b,int c,int d){
Node ans;
ans.a[0]=a;ans.a[1]=b;
ans.a[2]=c;ans.a[3]=d;
return ans;
}
LL ans;
int idx,head[M],cne;
struct Edge{
int v,next;
}adj[M*2],ade[M*2];
int stk[M],tp,sccno[M];
int scnt,dfn[M],low[M],rd[M],idk;
LL rsiz[M];
void ins(int x,int y){
adj[++idx].v=y;
adj[idx].next=head[x];
head[x]=idx;
}
LL dp[M];
void init(){
cne=0;idk=0;
cnt=0;ans=0;tp=0;scnt=0;
idx=0;
for(int i=1;i<=n;i++){
for(int k=0;k<4;k++){
A[i].b[k]=A[i].c[k]=0;
}
}
for(int i=0;i<=K;i++)
for(int j=0;i+j<=K;j++)
for(int k=0;i+j+k<=K;k++){
int l=K-i-j-k;
id[i][j][k][l]=++cnt;
sccno[cnt]=dfn[cnt]=0;
low[cnt]=0;
head[cnt]=0;
dp[cnt]=0;
rd[cnt]=0;rsiz[cnt]=0;
idv[cnt]=inp(i,j,k,l);
siz[cnt]=cal(idv[cnt]);
}
}
void tarjan(int x){
dfn[x]=low[x]=++idk;
stk[++tp]=x;
for(int i=head[x];i;i=adj[i].next){
int v=adj[i].v;
if(!dfn[v]){
tarjan(v);
low[x]=min(low[v],low[x]);
}
else if(!sccno[v])low[x]=min(dfn[v],low[x]);
}
if(low[x]==dfn[x]){
scnt++;
while(tp>0){
int v=stk[tp--];
sccno[v]=scnt;
rsiz[scnt]+=siz[v];
if(v==x)break;
}
}
}
LL dfs(int x){
if(dp[x])return dp[x];
dp[x]=rsiz[x];
for(int i=head[x];i;i=adj[i].next){
int v=adj[i].v;
dp[x]=max(dp[x],rsiz[x]+dfs(v));
}
return dp[x];
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
for(int i=0;i<=50;i++)
f[i][0]=f[i][i]=1;
for(int i=2;i<=50;i++)
for(int j=1;j<i;j++)
f[i][j]=f[i-1][j]+f[i-1][j-1];
cin>>G;
while(G--){
cin>>K>>n;
init();
for(int i=1;i<=n;i++){
string B;
cin>>B;
for(int j=0;j<B.size();j++)
for(int k=0;k<4;k++)
A[i].b[k]+=(B[j]==(char)(k+'A'));
}
for(int i=1;i<=n;i++){
string C;
cin>>C;
for(int j=0;j<C.size();j++)
for(int k=0;k<4;k++)
A[i].c[k]+=(C[j]==(char)(k+'A'));
}
sort(A+1,A+1+n,cmp);
n=unique(A+1,A+1+n)-(A+1);
for(int i=1;i<=cnt;i++){
for(int j=1;j<=n;j++){
Node arg=idv[i];
Node leo=inp(A[j].b[0],A[j].b[1],A[j].b[2],A[j].b[3]);
Node oel=inp(A[j].c[0],A[j].c[1],A[j].c[2],A[j].c[3]);
if(arg>=leo){
Node tr=arg-leo+oel;
ins(i,gt(tr));
ade[++cne]=(Edge){i,gt(tr)};
}
}
}
for(int i=1;i<=cnt;i++){
if(!dfn[i])tarjan(i);
}
idx=0;
for(int i=1;i<=scnt;i++)
head[i]=0;
for(int i=1;i<=cne;i++){
if(sccno[ade[i].v]!=sccno[ade[i].next]){
ins(sccno[ade[i].v],sccno[ade[i].next]);
rd[sccno[ade[i].next]]++;
}
}
for(int i=1;i<=scnt;i++){
if(!rd[i]){
ans=max(ans,dfs(i));
}
}
cout<<ans<<'\n';
}
return 0;
}

浙公网安备 33010602011771号