题目
思路来源
小羊肖恩
题解
羊神这个做法tql,当时只是机械地写,过了之后再想想,才觉得确实是nb
先扩展kmp(Z函数)预处理出来数组,记z[i]为i往后可以和前缀匹配的最大长度
对于每个询问(p,cnt),先离线归位到每个p所在的vector内,
然后扫描线,每个i有一个[i,i+z[i]-1]的区间,在这个区间内以j结尾时,和前缀的lcp固定为[i,j]
对于每个i,先特判只出现一次的情况
对于大于一次的情况,先二分当前最大的可行长度x,
这个需要预处理mn[i][j]表示前i个字符出现j次时的结尾处的最小下标,没有的话就是n+1
对于位置p,出现次数cnt,二分找到满足mn[x][cnt]<=p的最大x,
长度x的前缀出现了cnt次,那么短于长度x的前缀一定出现了cnt次,
然后[i,i+z[i]-1]的扫描线保证了以p结尾的一定是一个当前合法的A串,
这就保证了A在开头和结尾均出现,且总的出现次数不少于cnt次了
一开始暴力双指针预处理mn超时了,后来改成在set上二分就ac了
因为长的串对应的位置一定包含短串,所以可以按zi从大到小释放位置,放进set,在set里二分
代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define scll(a) scanf("%lld",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=2e5+10;
struct BitPre{ // 求前缀和(可改为max等)int n,tr[N];void init(int _n){n=_n;memset(tr,0,(n+1)*sizeof(*tr));}void add(int x,int v){++x;for(int i=x;i<=n;i+=i&-i)tr[i]+=v;}int sum(int x){++x;int ans=0; for(int i=x;i;i-=i&-i)ans+=tr[i];return ans;}
}tr;
int n,m,net[N],ans[N];
char s[N];
P ask[N];
vector<int>q[N],add[N],del[N],mn[N];
void extkmppre(char s[],int len){int i=0,j,pos;net[0]=len;while(i+1<len&&s[i]==s[i+1])i++;net[1]=i,pos=1;rep(i,2,len-1){if(net[i-pos]+i<net[pos]+pos){net[i]=net[i-pos];}else{j=net[pos]+pos-i;if(j<0)j=0;while(i+j<len&&s[j]==s[i+j])j++;net[i]=j,pos=i;}}
}
void init(){set<int>S;vector<vector<int> >in(n+1,vector<int>());rep(i,0,n-1){in[net[i]].pb(i);}per(i,n,1){for(auto &x:in[i]){S.insert(x);}int up=n/i+1;mn[i].resize(up);mn[i][0]=0;mn[i][1]=i-1;//printf("i:%d up:%d\n",i,up);rep(j,2,up-1){if(mn[i][j-1]>n){mn[i][j]=n+1;continue;}auto it=S.upper_bound(mn[i][j-1]);if(it==S.end()){mn[i][j]=n+1;}else{mn[i][j]=(*it)+i-1;}//printf("i:%d j:%d mn:%d\n",i,j,mn[i][j]);}}rep(i,0,n-1){add[i].pb(i);del[i+net[i]-1].pb(i);}
}
bool ok(int len,int cnt,int p){if(!len)return 1;if(1ll*len*cnt>p+1)return 0;return mn[len][cnt]<=p;//printf("len:%d ok:%1d\n",len,o);//"cnt:%d p:%d mn:%d net:%d\n",len,cnt,p,mn[len][cnt],net[p-len+1]);//return o;
}
int main(){sci(n);scanf("%s",s);extkmppre(s,n);// rep(i,0,n-1){// printf("i:%d z[i]:%d\n",i,net[i]);// }init();tr.init(n+1);sci(m);rep(i,1,m){sci(ask[i].fi);sci(ask[i].se);ask[i].fi--;q[ask[i].fi].pb(i);}rep(i,0,n-1){for(auto &x:add[i]){tr.add(x,1);}for(auto &x:q[i]){int p=ask[x].fi,c=ask[x].se;if(c==1){ans[x]=1;continue;}int l=0,r=n;while(l<=r){int mid=(l+r)/2;if(ok(mid,c,i))l=mid+1;else r=mid-1;}//printf("id:%d p:%d c:%d len:%d\n",x,p,c,r);if(r==0)ans[x]=0;else ans[x]=tr.sum(i)-tr.sum(i-r);// rep(j,1,i){// printf("%d ",tr.sum(j)-tr.sum(j-1));// }// puts("");}for(auto &x:del[i]){tr.add(x,-1);}}rep(i,1,m){printf("%d\n",ans[i]);}return 0;
}