ZJNU 2035 - Mate
给定一段字符串S
给定Q次询问,每次询问存在多少个长度为D的子串(char型子序列),以字母AB结尾
|S|最大为2000,Q最大为50w
显而易见,我们只考虑结尾为AB字符的子串
所以可以根据A的位置,求出A位置前有多少字符,用组合数可以求出能够得到多少组合
即假设某个字符A的位置为p,则A前字符组合个数为 C[D-2][p-1] ,即从p-1个字符中取D-2个字符的取法数
然后考虑B字符,只需要后缀处理一下到某个位置时某个字符出现次数即可,采用结构体或者二维数组均可
对于A的位置,采用vector或是26个数组+26个计数变量记录每种字符出现的所有位置下标,再从中循环一遍即可
最后答案为Σ (p∈A) C[D-2][p-1] * count { B -> p+1~Len } (%1e9+7)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; struct node{ int v[26]; }ar[2050]; vector<int> vec[26]; char s[2050]; int C[2050][2050]; void solve(){ int Q,D,i,cnt,pos; char ch[5]; cin>>Q; while(Q--){ ll ans=0; cin>>D>>ch; cnt=vec[ch[0]-'a'].size(); for(i=0;i<cnt;i++){ pos=vec[ch[0]-'a'][i]; ans=(ans+1LL*ar[pos+1].v[ch[1]-'a']*C[D-2][pos-1])%mod; } cout<<ans<<'\n'; } } int main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int i,j,len; C[0][0]=C[0][1]=C[1][1]=1; for(i=2;i<=2000;i++){ C[0][i]=C[i][i]=1; for(j=1;j<i;j++) C[j][i]=(C[j][i-1]+C[j-1][i-1])%mod; }//杨辉三角求组合数 cin>>(s+1); len=strlen(s+1); for(i=0;i<26;i++) ar[len].v[i]=0; ar[len].v[s[len]-'a']=1; vec[s[len]-'a'].push_back(len); for(i=len-1;i;i--){ ar[i]=ar[i+1]; ar[i].v[s[i]-'a']++;//后缀预处理 vec[s[i]-'a'].push_back(i);//位置储存 } solve(); return 0; }