P1366 有序表的合并 题解

发布时间 2023-08-22 22:01:22作者: Thenyu

题目给出两个数列 $a$,$b$,均按不降序排序,要求 $a$ 数列中的数在 $b$ 数列中出现多少次。

刚开始是想用一个数组来记录 $b$ 数列中的数出现的次数,然后再枚举 $a$ 数列中的每个数是否在 $b$ 数列中出现来累计答案,但是后面看到 $ 1 \leq n, m \leq 10^7 $ 就放弃了这个想法。

因为 $a$,$b$ 两个数列均按不降序排序,所以可以用一个指针 $ida$ 依次遍历 $a$ 数列中的每一个数,然后再用另一个指针 $idb$ 遍历 $b$ 数列,当 $a_{ida}$ $ = $ $b_{idb}$ 且 $ idb \leq m $ 时则为 $a$ 数列中的数在 $b$ 数列中出现一次,累加到计数器里并且指针 $ idb \gets idb+1 $ 指向 $b$ 数列中的下一个数,如果当 $a_{ida}$ $ > $ $b_{idb}$ 且 $ idb \leq m $ 时就只将指针 $ idb \gets idb+1 $ 指向 $b$ 数列中的下一个数,最后再将答案与计数器中的数异或就行了。

AC 代码

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e7;
int t,n,m;
ull a[N+5],b[N+5];
inline ull read()
{
	ull x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x*f;
}
int main()
{
	t=read();
	while(t--)
	{
		n=read(),m=read();
		for(int i=1;i<=n;++i)
			a[i]=read();
		for(int i=1;i<=m;++i)
			b[i]=read();
		int idb=1,tmp=0,ans=0;
		for(int ida=1;ida<=n;++ida)//依次遍历数列a中的每一个数 
		{
			while(a[ida]>=b[idb] && idb<=m)//a数列当前指针指向的位置上的数大于等于b数列指针指向位置的数,那么a数列中的这个数只会出现在b数列idb及idb后面的位置上 
			{
				if(a[ida]==b[idb])++tmp;//相同即为a数列中的数在b数列中出现一次,累加到计数器tmp中 
				++idb;//遍历b数列下一个数 
			}
			ans^=tmp,tmp=0;
		}
		printf("%d\n",ans);
	}
	return 0;
}