zoukankan      html  css  js  c++  java
  • 洛谷 P6273 [eJOI2017]魔法(前缀和+排序)

    洛谷 P6273 [eJOI2017]魔法

    题目

    • 给定一个长度为 n n n的字符串 S S S。设 S S S的不同的字符数为 k k k
    • 定义字符串的子串为该字符串某一连续段。
    • 而有魔法的子串被定义为 S S S的某一非空子串,满足该子串中不同的字符数为 k k k,且每个字符的出现的次数都相同。
    • 你需要求出给定字符串 S S S的不同的有魔法的子串的个数。
    • 若两个子串的左右端点不同,则这两个子串不同。
    • 对于所有数据,保证 2 ≤ n ≤ 1 0 5 2le nle 10^5 2n105,字符集为 [ a , z ] ∪ [ A , Z ] [a,z]∪[A,Z] [a,z][A,Z]

    题解

    • 会发现一个区间如果满足条件,那么每种字符前缀和在 r r r位置和 l − 1 l-1 l1位置之差都相等,
    • 换种角度考虑, r r r位置和 l − 1 l-1 l1位置下,每两种字符前缀和之差都相等,
    • 所以可以把前缀和每个位置的各个字符和字符 a a a的值之差列出来,相同的两个位置代表的区间即符合条件,直接排序即可。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 100010
    char s[N];
    int f[55], p[55], r = 0;
    struct node {
    	int p[55];
    }a[N];
    int cmp(node x, node y) {
    	for(int i = 0; i < r; i++) {
    		if(x.p[i] < y.p[i]) return 1;
    		if(x.p[i] > y.p[i]) return 0;
    	}
    	return 0;
    }
    int main() {
    	int n, i, j;
    	scanf("%d", &n);
    	scanf("%s", s + 1);
    	for(i = 1; i <= n; i++) {
    		if(s[i] <= 'Z') p[s[i] - 'A'] = 1;
    		else p[s[i] - 'a' + 26] = 1;
    	}
    	for(i = 0; i < 52; i++) {
    		if(p[i]) p[i] = r, r++;
    	}
    	for(i = 1; i <= n; i++) {
    		if(s[i] <= 'Z') f[p[s[i] - 'A']]++;
    		else f[p[s[i] - 'a' + 26]]++;
    		for(j = 0; j < r; j++) a[i].p[j] = f[j] - f[0];
    	}
    	sort(a, a + n + 1, cmp);
    	long long ans = 0, t = 0;
    	for(i = 0; i <= n; i++) {
    		if(i == 0 || cmp(a[i - 1], a[i]) == 1) {
    			t = 1;
    		}
    		else  {
    			ans += t;
    			t++;
    		}
    	}
    	printf("%lld", ans % 1000000007);
    	return 0;
    }
    
  • 相关阅读:
    面试生信工程师2
    R语言矩阵相关性计算及其可视化?
    PCA方差解释比例求解与绘图?
    MySQL 练习
    oracle高级数据查询技术
    Oracle安全管理
    基本查询语句
    管理表
    oracle PL/SQL高级编程
    oracle视图与索引
  • 原文地址:https://www.cnblogs.com/LZA119/p/14279512.html
Copyright © 2011-2022 走看看