CF888C K-Dominant Character 题解

楼上的 O ( n ) O(n) O(n)题解太强了,本菜鸡来说一说其他做法

这个题目看到的第一感觉就是二分答案,因为又是要求最小值且答案有单调性

n = ∣ S ∣ n=|S| n=S,二分最小的 k k k,然后 O ( n ) O(n) O(n)的扫出每个字串,把每个字串的字符信息保存,然后判断每一个字串是否有公共字符。

我们发现这样做有一些浪费时间,因为每个字串的字符信息是不会变的,于是我们可以把它前缀和记录一下

s u m [ i ] [ j ] sum[i][j] sum[i][j]表示前i个字符字符j出现的次数,然后枚举字串起点 l l l和终点 r r r,每个字符出现的次数就是 s u m [ r ] [ j ] − s u m [ l − 1 ] [ j ] sum[r][j]-sum[l-1][j] sum[r][j]sum[l1][j]就好了

优化完的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

w o w ! wow! wow!

n n n 1 0 5 10^5 105这。。。二分也能过,出题人tql

#include <map>
#include <set>
#include <ctime>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
#include <bitset>
#include <cstdio>
#include <cctype>
#include <string>
#include <cstring>
#include <cassert>
#include <climits>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std ;
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define per(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
#define clr(a) memset(a, 0, sizeof(a))
#define ass(a, sum) memset(a, sum, sizeof(a))
#define lowbit(x) (x & -x)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define enter cout << endl
#define siz(x) ((int)x.size())
typedef long long ll ;
typedef unsigned long long ull ;
typedef vector <int> vi ;
typedef pair <int, int> pii ;
typedef map <int, int> mii ;
typedef map <string, int> msi ;
const int N = 100010 ;
const int M = 30 ;
const int INF = 0x3f3f3f3f ;
const int iinf = 1 << 30 ;
const ll linf = 2e18 ;
const int MOD = 1000000007 ;
void print(int x) { cout << x << endl ; exit(0) ; }
void PRINT(string x) { cout << x << endl ; exit(0) ; }
void douout(double x){ printf("%lf\n", x + 0.0000000001) ; }

int a[M], b[M] ;
int sum[N][M] ;
char s[N] ;
int n ;

bool check(int x) {
    for (int i = 1; i <= 26; i++) b[i] = iinf ;
    for (int r = x; r <= n; r++) {
        int l = r - x + 1 ;
        for (int i = 1; i <= 26; i++) a[i] = sum[r][i] - sum[l - 1][i] ;
        for (int i = 1; i <= 26; i++) b[i] = min(b[i], a[i]) ;
    }
    for (int i = 1; i <= 26; i++) if (b[i]) return true ;
    return false ;
}

signed main(){
    scanf("%s", s + 1) ; n = strlen(s + 1) ;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= 26; j++) sum[i][j] = sum[i - 1][j] ;
        sum[i][s[i] - 'a' + 1]++ ;
    }
    int l = 0, r = n + 1 ;
    while (l + 1 < r) {
        int mid = (l + r) >> 1 ;
        if (check(mid)) r = mid ;
        else l = mid ;
    }
    printf("%d\n", r) ;
    return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值