解析:1.子序列的含义。这里的子序列与我们以前所认知的略有不同,是数学意义上的子序列。
在数学中,某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。 例如{1,3,2} 是{1,4,3,5,2,1}的一个子序列.
2.求环。BC的题解里就有一个求环,然后累加长度,更详细的解释就没了,这里就详细解释一下。
对于每个a[i],b[i]有两种情况:
①b[i]==a[i]
在这种情况下,(<( ̄︶ ̄)> 你以为我要说什么?作为特例记下来就好)
②b[i]!=a[i]
这种情况下,若a[i]要参与到最长子序列中,就只能是错位了。比如这样的一组数据:
1 3 2 4
3 2 4 1
错一位,变成这样:
1 3 2 4
3 2 4 1
最长子序列即为:3 2 4
这要怎么处理呢?
a1-->b3-->a3-->b2-->a2-->b4-->a4-->b1-->a1
也就是说,从数字 1 出发,通过A数列与B数列的一一对应关系,最终肯定会回到1,这就是一个环。在这个环中,A的长度==B的长度==4,子序列长度为3,这也就是为什么会有 L>1时,ans+=L-1。
3.官方给的题解是,找到所有环L,若L==1(也就是a[i]==b[i]),ans+=1;若L>1,ans+=L-1。
但实际上,由于两个数列都是从1到n的n个数,也就说两个数列必然是由 环 所组成。所以只要求出L>1的环的数量 J ,ans=n-J。
代码:
#include
#include
#include
using namespace std;
const int maxn=1e5;
int a[maxn +10],b[maxn+10];
bool v[maxn+10];
int getin()
{
int ans=0;char tmp;
while(!isdigit(tmp=getchar()));
do ans=(ans<<3)+(ans<<1)+tmp-'0';
while(isdigit(tmp=getchar()));
return ans;
}
int main()
{
freopen("1.in","r",stdin);
int t,n,ans,i,j,k;
for(t=getin();t>0;t--)
{
ans=n=getin();
for(i=1;i<=n;i++)a[i]=getin();
for(i=1;i<=n;i++)b[a[i]]=getin();
memset(v,0,sizeof(v));
for(i=1;i<=n;i++)if(!v[i] && b[i]!=i)
for(--ans,k=i;!v[k];k=b[k])v[k]=1;
printf("%d\n",ans);
}
return 0;
}