题解:AT_arc053_d [ARC053D] 2 つの山札
更好的阅读体验
打模拟赛被这个题伏击了,于是决定记录一下。
首先进行一个转化:建一个
我们要求的,就是
我们考虑
但是
显然
接下来考虑
我们考虑两条重复的路径是怎么样。我们枚举这两条路径最后一次相交的位置
接下来考虑
我们发现,这两条路径一定会同时转向。
考虑反证。如果存在一个地方两条路径不同时转向,那么就会有两条路径在某一个时刻是平行的;由于
由这个观察我们进一步发现,这两条路径一定关于一条斜率为
我们再考虑这条路径在什么时候可以转向。显然只有满足
我们把转向的点延长到那条直线上,与直线的交点
由此每条和这条直线不交的路径都对应着一条与其本质相同的,关于这条直线对称的路径。我们只对其中一条计数,就可以计算出重复的数量
由上图中的五角星,我们可以得到转向的最大次数。我们假设
所以当
看起来是
#include<bits/stdc++.h>
#define endl '\n'
#define N 2006
#define MOD 1000000007
using namespace std;
inline void add(int &x,int y) {x+=y,x-=x>=MOD?MOD:0;}
inline void dec(int &x,int y) {x+=MOD-y,x-=x>=MOD?MOD:0;}
int n,a[N],b[N],fac[N],ifac[N],f[N][N];
inline int qpow(int x,int y=MOD-2)
{
int ret=1;
for(;y;y>>=1,x=1ll*x*x%MOD)if(y&1)ret=1ll*ret*x%MOD;
return ret;
}
void init()
{
fac[0]=1;
for(int i=1;i<N;i++)fac[i]=1ll*i*fac[i-1]%MOD;
ifac[N-1]=qpow(fac[N-1]);
for(int i=N-2;~i;i--)ifac[i]=1ll*(i+1)*ifac[i+1]%MOD;
}
inline int binom(int x,int y) {return x<y?0:1ll*fac[x]*ifac[y]%MOD*ifac[x-y]%MOD;}
inline int cat(int x) {return (binom(2*x,x)-binom(2*x,x-1)+MOD)%MOD;}
main()
{
scanf("%d",&n),init(),f[1][1]=1;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)if(i!=1||j!=1)
{
f[i][j]=(f[i-1][j]+f[i][j-1])%MOD;
if(a[i]!=b[j])continue;
for(int k=1,cnt=0;k<min(i,j);k++)
if(a[i-k]==b[j-k])cnt++,dec(f[i][j],1ll*f[i-k][j-k]*cat(cnt-1)%MOD);
}
printf("%d\n",f[n][n]);
return 0;
}