ZJNU 2035

给定一段字符串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<<'
';
    }
}
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;
}
原文地址:https://www.cnblogs.com/stelayuri/p/12420861.html