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<algorithm>
#include<iostream>
#include <cstdio>
#include <string>
#include <queue>
#include <cstring>
#include <stack>
#include <bitset>
#include <set>
#include <unordered_set>
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);
}
}