杭电多校第八场 Kidnapper‘s Matching Problem 线性基 kmp

Kidnapper’s Matching Problem

题目链接

题目大意

给一个长度为n的数组a,长度为m的数组b,长度为k的数组s。
从a数组中选一个长度为m的连续子序列跟b数组两两匹配。
配对只能是这样配:(a[l], b[1]), (a[l + 1], b[2]), (a[l + 2], b[3]) ……
使得a[l + i - 1] ^ b[i] 能在s中选一些数异或得到。
也就是a[l + i - 1] ^ b[i] 在s的线性基里出现。

题解

还是蠢啊,干不出来
假设 a ^ b 在s的线性基里出现。
设s的线性基是D。
那么把a中消去D中的位得到a’
把b消去D中的位得到b’
那么a‘ == b’
。。
于是就可以把a数组中的数全部消去D中的位,b数组中的全部也消去D中的位。然后找a中长度为m的连续子序列等于b就好
于是就比较简单了。。kmp板子。。

代码

#include
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef unordered_set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void tempwj(){freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b > 0){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second < b.second;}};
int lb(int x){return  x & -x;}
//friend bool operator < (Node a,Node b)   重载
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9+7;
const int maxn = 2e5+10;


int d[40];
void add(int x)
{
	for (int i = 30; i >= 0; i -- )
	{
		if(x >> i & 1)
		{
			if(d[i])
				x ^= d[i];
			else
			{
				d[i] = x;
				return;
			}
		}
	}
}
int getans(int x)
{
	for (int  i= 30; i >= 0; i -- )
	{
		if(x >> i & 1)
		{
			x ^= d[i];
		}
	}
	return x;
}
int s[maxn];
int a[maxn];
int b[maxn];
int nxt[maxn];
void getnxt(int m)
{
	int k = -1;
	int j = 0;
	nxt[0] = -1;
	while(j < m)
	{
		if(k == -1 || b[j] == b[k])
			nxt[++j] = ++ k;
		else
			k = nxt[k];
	}
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T -- )
	{
		memset(d,0,sizeof(d));
		int n,m,k;
		scanf("%d%d%d",&n,&m,&k);
		for (int i = 0; i < n; i ++ )
			scanf("%d",&a[i]);
		for (int j = 0; j < m; j ++ )
			scanf("%d",&b[j]);
		for (int i = 1; i <= k; i ++ )
		{
			scanf("%d",&s[i]);
			add(s[i]);
		}
		for (int  i= 0; i < n; i ++ )
			a[i] = getans(a[i]);
		for (int i = 0; i < m; i ++ )
			b[i] = getans(b[i]);
		getnxt(m);
		int j = 0;
		ll ans = 0;
		// for (int  i=0; i < n; i++ )
		// 	printf("%d ",a[i]);
		// printf("\n");
		// for (int i = 0; i < m; i ++ )
		// 	printf("%d ",b[i]);
		// printf("\n");
		for (int i = 0; i < n; )
		{
			if(j == -1 || a[i] == b[j])
			{
				i ++ ;
				j ++ ;
			}
			else
				j = nxt[j];
			// printf("%d %d\n",i,j);
			if(j == m)
			{
				// printf("%d\n",i);
				ans = ans + qpow(2,i - m,mod);
				ans %= mod;
				j = nxt[j];
			}
		}
		printf("%lld\n",ans);
	}
}

你可能感兴趣的:(做题笔记)