• 在这冷漠的世界里光光哭哭 题解(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;
    }
    
    
  • 相关阅读:
    喜讯|恒生电子LightDB完成分布式数据产品稳定性测试
    PostgreSQL limit的ties子句
    实时通信 | pusher 如何使用私有频道(四)
    实时通信 | pusher 客户端事件(五)
    实时通信 | pusher 案例:实时图表(六)
    实时通信 | pusher 演示与频道实时通信(三)
    PHP系列 | MeiliSearch 轻量搜索引擎入门介绍
    实时通信 | pusher 频道介绍(二)
    实时通信 | pusher 入门教程(一)
    袁创:总结创业十年经验
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/15874902.html
Copyright © 2020-2023  润新知