JZOJ5711. 【北大夏令营2018模拟5.13】时间幻象
程序员文章站
2022-05-15 14:02:40
...
题目大意
要求出一个长度为n,且仅由ABCD四个字母组成的字符串,
通过给出的m种变化方式,以及任意交换相邻的两个,得出尽可能多的字符串。
题解
任意交换相邻的两个位置,也就是说当ABCD的个数确定的时候,就可以通关交换两个相邻的,弄出全排列。
其实,只需要记录ABC的个数就可以了,D的个数是可以直接算出来的。
n只有30,估算一下最多的状态数只有不到6000,那么考虑转移,也就是只有m*状态数。
这样以ABC的数量为点,根据给出的条件连有向边。
现在题目就变成了求图中的最长路,
就先用tarjan缩点,对于一个强连通分量里面是所有点,可以从任意一个位置进去,然后走完整个环之后,再从任意一个位置出来,根据拓扑序求出最长路就好了。
code
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#define ll long long
#define N 150003
#define M 33
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int ti,dfn[N],low[N],z[N],g[N],cnt,ta;
int lst[N],nxt[N],to[N],tot;
int lst_[N],nxt_[N],to_[N],tot_;
int n,m,t1[5],t2[5],t[5],id[M][M][M],w,tt;
int q[N],d[N],l,r,x;
int s[M][M],sum[M];
long long f[N],V[N],F[N],ans;
bool bz[N];
void tarjan(int x)
{
ti++;
dfn[x]=low[x]=ti;
bz[x]=0;
ta++;
z[ta]=x;
for(int i=lst[x];i;i=nxt[i])
{
if(dfn[to[i]]==0)
{
tarjan(to[i]);
low[x]=min(low[x],low[to[i]]);
}
else if(!bz[to[i]])low[x]=min(low[x],dfn[to[i]]);
}
if(low[x]==dfn[x])
{
for(cnt++;z[ta]!=x && ta;ta--)F[g[z[ta]]=cnt]+=V[z[ta]],bz[z[ta]]=1;
F[g[z[ta]]=cnt]+=V[z[ta]],bz[z[ta]]=1;
ta--;
}
}
void ins(int x,int y)
{
nxt[++tot]=lst[x];
to[tot]=y;
lst[x]=tot;
}
void ins_(int x,int y)
{
nxt_[++tot_]=lst_[x];
to_[tot_]=y;
lst_[x]=tot_;
}
void re()
{
memset(t1,0,sizeof(t1));
memset(t2,0,sizeof(t2));
for(ch=G();ch<'A' || ch>'D';ch=G());
for(;'A'<=ch && ch<='D';ch=G())t1[ch-'A']++;
for(ch=G();ch<'A' || ch>'D';ch=G());
for(;'A'<=ch && ch<='D';ch=G())t2[ch-'A']++;
for(int i=0;i<5;i++)t[i]=t2[i]-t1[i];
}
void pre()
{
for(register int i=1;i<M;i++)
{
int t=i;
for(register int j=2;j<M;j++)
{
s[i][j]+=s[i-1][j];
for(;t%j==0;t=t/j)s[i][j]++;
}
s[i][t]++;
}
}
ll ksm(ll x,int y)
{
ll s=1;
for(;y;y>>=1,x=x*x)
if(y&1)s=s*x;
return s;
}
void get()
{
for(register int i=0;i<=n;i++)
for(register int j=0;j+i<=n;j++)
for(register int k=0;k+i+j<=n;k++)
{
V[id[i][j][k]]=1;
for(int w=2;w<M;w++)
V[id[i][j][k]]*=ksm(w,s[n][w]-s[i][w]-s[j][w]-s[k][w]-s[n-i-j-k][w]);
}
}
int main()
{
freopen("return.in","r",stdin);
freopen("return.out","w",stdout);
pre();read(n);
for(register int i=0;i<=n;i++)
for(register int j=0;j+i<=n;j++)
for(register int k=0;k+i+j<=n;k++)
id[i][j][k]=++w;
for(read(m),get();m;m--)
{
re();
for(register int i=0;i<=n;i++)
if(t[0]+i<=n && i>=t1[0])
for(register int j=0;j+i<=n;j++)
if(t[1]+j<=n && j>=t1[1])
for(register int k=0;k+i+j<=n;k++)
if(t[2]+k<=n && k>=t1[2])
{
tt=n-i-j-k;
if(t[3]+tt>n || tt<t1[3])continue;
ins(id[i][j][k],id[i+t[0]][j+t[1]][k+t[2]]);
}
}
memset(bz,1,sizeof(bz));
for(register int i=1;i<=w;i++)
if(dfn[i]==0)tarjan(i);
for(register int i=1;i<=w;i++)
for(register int j=lst[i];j;j=nxt[j])
if(g[i]!=g[to[j]])ins_(g[i],g[to[j]]),d[g[to[j]]]++;
for(register int i=1;i<=w;i++)
if(d[i]==0)q[++r]=i,f[i]=0;
for(l=0;l<r;)
{
f[x=q[++l]]+=F[x];
for(register int i=lst_[x];i;i=nxt_[i])
{
f[to_[i]]=max(f[to_[i]],f[x]);
d[to_[i]]--;
if(d[to_[i]]==0)q[++r]=to_[i];
}
ans=max(ans,f[x]);
}
printf("%lld",ans);
return 0;
}