在这冷漠的世界里光光哭哭 题解(dp+思维+容斥)

题目链接

题目思路

本质上就是一堆容斥搞一搞

直接放官方题解

唯一有点描述不准确的是第二行里\(dp[k][i][j]\)表示的应该是\(x\)字母在前\(k\)个字符的所有\(ixj\)序列个数

代码

#include<bits/stdc++.h>
#define double long double
#define ll long long
#define fi first
#define se second
using namespace std;
const int maxn=8e4+5;
int n,q;
char s[maxn];
vector<int> g[30];
ll pre1[maxn][27];
// pre1[i][j] 表示前i个元素有多少个j
ll pre2[maxn][27][27];
// pre2[i][j][k] 表示前i个元素有多少个 jk子序列
ll dp[maxn][27][27],tmp[30][30][30];
//对于第 k 个字符是x ,字符串的前 k 个字符里,包含子序列 "ixj" 的数量是 dp[k][i][j] 。注意,这里的 "ixj" 中的 i 和 j 分别代表第 i 个字母和第 j 个字母
// 说前k个有点不严谨,因为其实知识x为前k个,还包含了后面的字符
ll cal(int l,int r,int a,int b){// 计算[l,r]区间有多少个ab子序列
    return pre2[r][a][b]-pre2[l-1][a][b]-pre1[l-1][a]*(pre1[r][b]-pre1[l-1][b]);
}
signed main(){
    scanf("%d%d %s",&n,&q,s+1);
    for(int i=1;i<=26;i++){
        g[i].push_back(0);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=26;j++){
            pre1[i][j]=pre1[i-1][j]+(s[i]=='a'+j-1);
        }
        for(int j=1;j<=26;j++){
            for(int k=1;k<=26;k++){
                pre2[i][j][k]=pre2[i-1][j][k];
                if(s[i]=='a'+k-1){
                    pre2[i][j][k]+=pre1[i-1][j];
                }
            }
        }
        g[s[i]-'a'+1].push_back(i);
    }
    for(int i=1;i<=26;i++){
        g[i].push_back(1e9);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=26;j++){
            for(int k=1;k<=26;k++){
                tmp[s[i]-'a'+1][j][k]+=pre1[i-1][j]*(pre1[n][k]-pre1[i][k]);
                dp[i][j][k]=tmp[s[i]-'a'+1][j][k];
            }
        }
    }
    for(int i=1,l,r;i<=q;i++){
        char t[10];
        scanf("%d%d %s",&l,&r,t+1);
        int a=t[1]-'a'+1;
        int b=t[2]-'a'+1;
        int c=t[3]-'a'+1;
        if(pre1[r][b]-pre1[l-1][b]==0){
            printf("0\n");
            continue;
        }
        int pos1=lower_bound(g[b].begin(),g[b].end(),l)-g[b].begin();
        int pos2=upper_bound(g[b].begin(),g[b].end(),r)-g[b].begin();
        ll ans=dp[g[b][pos2-1]][a][c]-dp[g[b][pos1-1]][a][c];
        ans-=pre1[l-1][a]*cal(l,r,b,c)+pre1[l-1][a]*(pre1[r][b]-pre1[l-1][b])*(pre1[n][c]-pre1[r][c])+cal(l,r,a,b)*(pre1[n][c]-pre1[r][c]);
        printf("%lld\n",ans);
    }
    return 0;
}

posted @ 2022-02-09 14:35  hunxuewangzi  阅读(65)  评论(0编辑  收藏  举报