「BJOI2020」封印
给出只包含小写字母 a a a, b b b的两个字符串 s s s, t t t, q q q次询问,每次询问 s [ l . . . r ] s[l...r] s[l...r]和 t t t的最长公共子串长度。
建出 t t t的后缀自动机后在自动机上跑 s s s串得到对于每个 s s s的前缀在 t t t中匹配的最长长度 p i p_i pi,然后对于 s [ l . . . r ] s[l...r] s[l...r],二分答案 m i d mid mid,检查是否有 max i = l + m i d − 1 r p i ≥ m i d \max_{i=l+mid-1}^rp_i \geq mid maxi=l+mid−1rpi≥mid即可。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define maxn 400005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define lim 18
using namespace std;
char s[maxn],t[maxn];
int q,ls,lt;
int last , fa[maxn] , len[maxn] , tr[maxn][2] , tot;
int st[lim][maxn] , lg[maxn];
void ins(int c){
int u = ++tot , p = last , q;
len[last = u] = len[p] + 1;
for(;p != -1 && !tr[p][c];p=fa[p]) tr[p][c] = u;
if(p == -1) fa[u] = 0;
else if(len[q = tr[p][c]] == len[p] + 1) fa[u] = q;
else{
int v = ++tot;
memcpy(tr[v],tr[q],sizeof tr[q]),fa[v] = fa[q] , len[v] = len[p] + 1;
for(;p != -1 && tr[p][c] == q;p=fa[p]) tr[p][c] = v;
fa[q] = fa[u] = v;
}
}
int qry(int u,int v){
int t = lg[v-u+1];
return max(st[t][u] , st[t][v-(1<<t)+1]);
}
int main(){
scanf("%s%s%d",s,t,&q);
fa[0] = -1;
ls = strlen(s) , lt = strlen(t);
rep(i,0,lt-1) ins(t[i] - 'a');
int u=0,L=0;
rep(i,0,ls-1){
int c = s[i] - 'a';
for(;u!=-1 && tr[u][c]==0;u=fa[u]);
if(u == -1) u = 0 , L = 0;
else L = min(L+1 , len[u] + 1) ,u = tr[u][c];
st[0][i] = L;
}
rep(i,2,ls) lg[i] = lg[i >> 1] + 1;
rep(j,1,lim-1) rep(i,0,ls-(1<<j))
st[j][i] = max(st[j-1][i] , st[j-1][i+(1<<j-1)]);
for(;q--;){
int l,r;scanf("%d%d",&l,&r);l--,r--;
int L = 0 , R = min(r-l+1,lt) , mid;
for(;L<R;){
mid = L+R+1 >> 1;
if(qry(l+mid-1,r) < mid) R = mid - 1;
else L = mid;
}
printf("%d\n",L);
}
}
LOJ #6537. 毒瘤题加强版再加强版
三倍经验
具体来说就是利用异或的性质,所有数异或起来等于出现奇数次的数的异或和。
如果我们要得到单独一个数字,就 h a s h hash hash一下,具体来说我们只统计 m o d p = i \bmod p = i modp=i的数的异或和。
那么多用几个 p p p,统计出来出现次数多的数就很有可能是单独一个数字的异或和,反之多个数字的异或和很难在多个不同的 p p p下都一起满足条件。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define vi vector<int>
using namespace std;
int chk(int x){
for(int i=2;i*i<=x;i++) if(x % i == 0) return 0;
return 1;
}
int n,K;
vi mod;
int a[20][20100];
map<int,int>mAp;
int main(){
scanf("%d%d",&n,&K);
for(int i=10000;mod.size() < 20;i++) if(chk(i) && rand() % 2)
mod.push_back(i);
for(int i=1;i<=n;i++){
int x;scanf("%d",&x);
for(int j=0;j<mod.size();j++)
a[j][x % mod[j]] ^= x;
}
for(int j=0;j<mod.size();j++) for(int i=0;i<mod[j];i++)
if(a[j][i]) mAp[a[j][i]]++;
vector<int>ans;
for(auto v:mAp) if(v.second > 2) ans.push_back(v.first);
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++) printf("%d\n",ans[i]);
}
CF963D Frequency of String
给出 S S S, Q Q Q次询问 S S S中最短的子串 t t t的长度使得字符串 m m m在 t t t中出现了 k k k次。
所有询问m互不相同。
可以想到求出后缀自动机的 r i g h t right right集合 S S S后 O ( ∣ S ∣ ) O(|S|) O(∣S∣)回答一次询问。
然后就这样写,然后就可以过。
因为所有询问 m m m互不相同,又因为对于所有长度为 k k k的串他们的 r i g h t right righ</