[NOI2021] 量子通信
\(\text{Problem}:\)[NOI2021] 量子通信
\(\text{Solution}:\)
首先有一个 \(O(\frac{256nm}{\omega})\) 的暴力做法。然后考虑如何将信息分段来优化匹配过程。
注意到 \(k_{max}=15\),而 \(256=16\times 16\),这提示可以将字典中的每个单词分为 \(16\) 段。不难发现,对于查询串,一定有某一段和某个单词是匹配的。枚举这一段和与其匹配的单词,暴力遍历其他段判断答案是否合法(不匹配的位置小于等于 \(k\))即可。
注意优化时间常数(如将 \(\text{vector}\) 换成数组等)。
\(\text{Code}:\)
#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
} char inp[256];
typedef unsigned long long ull;
const int MN = 400000;
//bool s[MN+1][256];
int wb[MN+1][16];
inline ull myRand(ull &k1, ull &k2) {
ull k3 = k1, k4 = k2;
k1 = k4;
k3 ^= (k3 << 23);
k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
return k2 + k4;
}
int g[16][65536][25],tot[16][65536]; int cnt[65536];
inline void gen(int n, ull a1, ull a2) {
for (ri int i = 1; i <= n; i++)
{
int now=0;
for (ri int j = 0; j < 256; j++)
{
//s[i][j] = (myRand(a1, a2) & (1ull << 32)) ? 1 : 0;
int du=j/16, pc=j%16;
if((myRand(a1, a2) & (1ull << 32))) now|=(1<<pc);
if(j%16==15) g[du][now][++tot[du][now]]=i, wb[i][du]=now, now=0;
}
}
}
int n,m,lsta; ull a1,a2;
int val[16];
inline void Read()
{
scanf("%s",inp);
for(ri int i=0;i<16;i++)
{
int now=0;
for(ri int j=0;j<4;j++)
{
int w,k=i*4+j;
if(inp[k]>='0'&&inp[k]<='9') w=inp[k]-'0';
else w=inp[k]-'A'+10;
if(lsta) w^=15;
for(ri int x=0;x<4;x++) if((w>>x)&1) now|=(1<<(j*4+3-x));
}
val[i]=now;
}
}
signed main()
{
//freopen("qi.in","r",stdin);
//freopen("qi.out","w",stdout);
scanf("%d%d%llu%llu",&n,&m,&a1,&a2);
gen(n,a1,a2);
for(ri int i=0;i<65536;i++) cnt[i]=cnt[i>>1]+(i&1);
for(ri int i=1;i<=m;i++)
{
Read(); int lim=read();
int flg=0;
for(ri int j=0;j<16;j++)
{
for(ri int k=1;k<=tot[j][val[j]];k++)
{
int id=g[j][val[j]][k];
int res=0;
for(ri int x=0;x<16;x++)
{
if(j==x) continue;
res+=cnt[val[x]^wb[id][x]];
if(res>lim) break;
}
if(res<=lim) { flg=1; break; }
}
if(flg) break;
}
printf("%d\n",lsta=flg);
}
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。