题解 路过中丹
首先手玩发现性质:
假如一个串存在两个相等的字符中间只隔着一个字符,那么这个串就一定“配得上丹”
否则是否“配得上丹”等价于是否存在偶回文覆盖(使用若干偶回文串覆盖所有字符)
前一个很好处理,考虑后一个怎么维护
一个方法是离线后扫描线
对于一个右端点 \(r\),若令线段树下标 \(i\) 处存能覆盖 \(i\) 的偶回文串左端点最大值
那么一个子区间 \([l, r]\) 合法的条件是这个区间的最小值 \(\geqslant l\)
维护的话需要知道以其为右端点的偶回文串左端点最大值
可以 manacher 求出来
- 貌似所有「覆盖范围随询问区间动态变化」的覆盖问题都可以离线下来扫描线处理?
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define fir first
#define sec second
#define pb push_back
#define ull unsigned long long
//#define int long long
int n, m;
char s[N];
namespace force{
int l, r;
bool vis[N];
string s2;
void dfs(int u, string s2, vector<int> pos, int t) {
if (s2.size()>4*(r-l+1)) return ;
s2.pb(s[u]); pos.pb(u);
if (u!=t) {
string tem=s2;
reverse(tem.begin(), tem.end());
if (tem==s2) for (auto it:pos) vis[it]=1;
}
if (u-1>=l) dfs(u-1, s2, pos, t);
if (u+1<=r) dfs(u+1, s2, pos, t);
}
void solve() {
for (int i=1; i<=m; ++i) {
// cerr<<"i: "<<i<<endl;
scanf("%d%d", &l, &r);
for (int j=l; j<=r; ++j) vis[j]=0;
for (int j=l; j<=r; ++j) dfs(j, string(), vector<int>(), j);
for (int j=l; j<=r; ++j) if (!vis[j]) {printf("0"); goto jump;}
printf("1");
jump: ;
}
printf("\n");
}
}
namespace task1{
bool vis[N];
void solve() {
for (int i=1,l,r; i<=m; ++i) {
scanf("%d%d", &l, &r);
for (int j=l+1; j<r; ++j) if (s[j-1]==s[j+1]) {printf("1"); goto jump;}
for (int j=l; j<=r; ++j) vis[j]=0;
for (int j=l; j<=r; ++j) {
for (int k=0; k<=min(j-l, r-j-1); ++k) {
if (s[j-k]==s[j+1+k]) vis[j-k]=vis[j+1+k]=1;
else break;
}
}
for (int j=l; j<=r; ++j) if (!vis[j]) {printf("0"); goto jump;}
printf("1");
jump: ;
}
printf("\n");
}
}
namespace task2{
bool vis[N];
ull h[N], rh[N], p[N];
int bit[N];
const ull base=13131;
inline ull hashing(int l, int r) {return h[r]-h[l-1]*p[r-l+1];}
inline ull rhash(int l, int r) {return rh[l]-rh[r+1]*p[r-l+1];}
inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) bit[i]+=dat;}
inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
void solve() {
p[0]=1;
for (int i=1; i<=n; ++i) p[i]=p[i-1]*base;
for (int i=1; i<=n; ++i) h[i]=h[i-1]*base+s[i];
for (int i=n; i; --i) rh[i]=rh[i+1]*base+s[i];
for (int i=1,l,r; i<=m; ++i) {
scanf("%d%d", &l, &r);
for (int j=l+1; j<r; ++j) if (s[j-1]==s[j+1]) {printf("1"); goto jump;}
for (int j=0; j<=n; ++j) bit[j]=0;
for (int j=l; j<r; ++j) if (s[j]==s[j+1]) {
// cout<<"j: "<<j<<endl;
int ql=1, qr=min(j-l+1, r-j), mid;
// cout<<"lr: "<<ql<<' '<<qr<<endl;
while (ql<=qr) {
mid=(ql+qr)>>1;
// cout<<"mid: "<<mid<<' '<<hashing(j-mid+1, j)<<' '<<rhash(j+1, j+mid)<<endl;
if (hashing(j-mid+1, j)==rhash(j+1, j+mid)) ql=mid+1;
else qr=mid-1;
}
int len=ql-1;
// cout<<"len: "<<len<<endl;
assert(j-len+1>=l && j+len<=r);
upd(j-len+1, 1); upd(j+len+1, -1);
}
for (int j=l; j<=r; ++j) if (query(j)==0) {printf("0"); goto jump;}
printf("1");
jump: ;
}
printf("\n");
}
}
namespace task{
char t[N<<1], *c;
bool ans[N];
pair<int, int> sta[N];
vector<pair<int, int>> que[N];
int tl[N<<2], tr[N<<2], mn[N<<2], tag[N<<2];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define mn(p) mn[p]
#define tag(p) tag[p]
#define pushup(p) mn(p)=min(mn(p<<1), mn(p<<1|1))
int bit[N], ql[N], qr[N], d[N<<1], lst[N], top;
inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) bit[i]+=dat;}
inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
void manacher() {
int n=0; c=s+1;
t[++n]='$'; t[++n]='#';
while (*c) t[++n]=*(c++), t[++n]='#';
for (int i=1,mid=0,r=0; i<=n; ++i) {
if (i<=r) d[i]=min(r-i+1, d[mid*2-i]);
while (t[i-d[i]]==t[i+d[i]]) ++d[i];
if (i+d[i]-1>r) r=i+d[i]-1, mid=i;
// cout<<sta[top].fir+sta[top].sec-1<<endl;
while (top && sta[top].fir+sta[top].sec-1<i) --top; //, cout<<"pop1"<<endl;
// cout<<"at "<<i<<": "; for (int i=1; i<=top; ++i) cout<<sta[i].fir<<','<<sta[i].sec<<' '; cout<<endl;
if (i&1) {
if (top) lst[i>>1]=(sta[top].fir*2-i)>>1;
// cout<<"pos1: "<<i<<endl;
}
else if (d[i]) {
while (top && sta[top].fir+sta[top].sec-1 <= i+d[i]-1) --top; //, cout<<"pop2"<<endl;
sta[++top]={i, d[i]};
}
}
// cout<<"lst: "; for (int i=1; i<=n; ++i) cout<<lst[i]<<' '; cout<<endl;
// cout<<"d: "; for (int i=1; i<=n*2; ++i) cout<<d[i]<<' '; cout<<endl;
// cout<<"t: "; for (int i=1; i<=n*2; ++i) cout<<t[i]<<' '; cout<<endl;
}
void spread(int p) {
if (!tag(p)) return ;
mn(p<<1)=max(mn(p<<1), tag(p)); tag(p<<1)=max(tag(p<<1), tag(p));
mn(p<<1|1)=max(mn(p<<1|1), tag(p)); tag(p<<1|1)=max(tag(p<<1|1), tag(p));
tag(p)=0;
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int l, int r, int val) {
if (l<=tl(p)&&r>=tr(p)) {mn(p)=max(mn(p), val); tag(p)=max(tag(p), val); return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) upd(p<<1, l, r, val);
if (r>mid) upd(p<<1|1, l, r, val);
pushup(p);
}
int query(int p, int l, int r) {
if (l<=tl(p)&&r>=tr(p)) return mn(p);
spread(p);
int mid=(tl(p)+tr(p))>>1, ans=INF;
if (l<=mid) ans=min(ans, query(p<<1, l, r));
if (r>mid) ans=min(ans, query(p<<1|1, l, r));
return ans;
}
void solve() {
manacher(); build(1, 1, n);
for (int i=2; i<n; ++i) if (s[i-1]==s[i+1]) upd(i, 1);
for (int i=1; i<=m; ++i) scanf("%d%d", &ql[i], &qr[i]), que[qr[i]].pb({ql[i], i});
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
if (lst[i]) upd(1, lst[i], i, lst[i]);
for (auto it:que[i]) ans[it.sec]=query(1, it.fir, i)>=it.fir;
}
for (int i=1,l,r; i<=m; ++i) {
l=ql[i], r=qr[i];
if (l==r) printf("0");
else if (query(r-1)-query(l)!=0) printf("1");
else if (ans[i]) printf("1");
else printf("0");
}
printf("\n");
}
}
signed main()
{
freopen("pass.in", "r", stdin);
freopen("pass.out", "w", stdout);
scanf("%d%s%d", &n, s+1, &m);
// force::solve();
// task1::solve();
// task2::solve();
task::solve();
return 0;
}