A Perfectly Balanced String(贪心/思维)

题目
题意:给定一个字符串 s s s,对于它的任意 ( t , u , v ) (t,u,v) (t,u,v),其中 t t t s s s的连续子串, u , v u,v u,v为出现在 s s s的字符,如果 u u u t t t的出现次数与 v v v t t t的出现次数的差值的绝对值,恒小于等于1,则说明字符串 s s s是平衡的。现给定字符串 s s s,判断它是否为平衡的。

参考

定理:定义 s s s中不同字符的个数为 k k k,长度为 n n n,如果对于任意的 0 < = i < n − k + 1 0<=i<n-k+1 0<=i<nk+1,长度为 k k k的子串 s [ i , i + k − 1 ] s[i,i+k-1] s[i,i+k1]上的字符都是不同的,则 s s s是平衡的。

必要性:如果存在子串 s [ i , i + k − 1 ] s[i,i+k-1] s[i,i+k1]的字符有相同的,则 s s s至少有一个字符v没出现在子串 s [ i , i + k − 1 ] s[i,i+k-1] s[i,i+k1]上,不妨设 s [ i , i + k − 1 ] s[i,i+k-1] s[i,i+k1]的相同字符为 u u u,则有 c o u n t ( u ) − c o u n t ( v ) > = 2 count(u)-count(v)>=2 count(u)count(v)>=2,因此 s s s是不平衡的。

充分性:如果对于任意的 0 < = i < n − k + 1 0<=i<n-k+1 0<=i<nk+1,长度为 k k k的子串 s [ i , i + k − 1 ] s[i,i+k-1] s[i,i+k1]上的字符都是不同的。对于任意的子串 s [ i , i + l − 1 ] s[i,i+l-1] s[i,i+l1],它可以拆分成 ⌈ l / k ⌉ \lceil l/k\rceil l/k段,除了最后一段,每一段上任意字符的出现次数都是1。因此任意字符,在子串 s [ i , i + l − 1 ] s[i,i+l-1] s[i,i+l1]的出现次数为 ⌈ l / k ⌉ \lceil l/k\rceil l/k,或者 ⌈ l / k ⌉ − 1 \lceil l/k\rceil-1 l/k1,因此,此时任意字符的在子串 s [ i , i + l − 1 ] s[i,i+l-1] s[i,i+l1]的出现次数的差值的绝对值,小于等于1。因此, s s s是平衡的。

上述定理也可以转化为 s s s的前 k k k个字符不同,对于任意 i > = k i>=k i>=k的字符,要求 s i = = s i − k s_i==s_{i-k} si==sik
官方代码

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int tc;
    cin >> tc;
    while(tc--)
    {
        string s;
        cin >> s;
        int n = s.length();
        set<char> c;
        bool ok = true;
        int k;
        for(k=0;k<n;k++)
        {
            if(c.find(s[k])==c.end())
                c.insert(s[k]);
            else
                break;
        }
        for(int i=k;i<n;i++)
        {
            if(s[i]!=s[i-k])
                ok = false;
        }
        if(ok)
            cout << "YES\n";
        else
            cout << "NO\n";
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值