游戏机本当下手(字符串+尺取)

链接:https://ac.nowcoder.com/acm/contest/8755/E
来源:牛客网

藤原妹红拿到了一个游戏机,游戏机上有'1'和'0'两个按钮。
妹红发现,只要按住某个按钮不放,屏幕上就能一直不断打印那个字符。
比如对于"11111111100000000001111111111",只需要按住1、再按住0、再按住1就可以打印出来了。这样妹红最少只需要按3次按钮就可以打印这个字符串。
现在妹红拿到了一个01字符串,她想截取其中的一个子串,这个子串最少按 次按钮就可以打印出来。
(01字符串指仅由字符'0'和字符'1'组成的字符串)
注意这里“最少按 次”的含义是:按 次可以打印出这个子串,但按 次就一定打印不出这个子串。
妹红想知道,一共有多少子串符合要求?
注:一个字符串的子串为该字符串删掉前面和后面部分字符(也可以不删)生成的字符串。
两个子串只要在字符串中位置不同则认为是不同的(哪怕字符串相等)。

输入描述:

第一行两个正整数 

,分别代表字符串的长度、和妹红按下按钮的次数。
第二行为一个仅由字符“0”和“1”组成的字符串。

输出描述:

妹红至少按 

次就能按出来的子串的数量。
示例1

输入

复制
6 2
001100

输出

复制
8

说明

注意到k=2,因此要寻找最少按2次就能打印的子串。
s[0,2]="001",妹红最少按2次就能按出来,先按0再按1。
s[0,3]="0011",妹红最少按2次就能按出来,先按0再按1。
s[1,2]="01",妹红最少按2次就能按出来,先按0再按1。
s[0,3]="011",妹红最少按2次就能按出来,先按0再按1。
s[2,4]="110",妹红最少按2次就能按出来,先按1再按0。
s[2,5]="1100",妹红最少按2次就能按出来,先按1再按0。
s[3,4]="10",妹红最少按2次就能按出来,先按1再按0。
s[3,5]="100",妹红最少按2次就能按出来,先按1再按0。
共有8个子串符合要求。
示例2

输入

复制
3 1
110

输出

复制
4

说明

注意到k=1,因此要寻找按1次就能打印的子串。
s[0,0]="1",妹红按住1就可以打印出来,只按了1次按钮
s[0,1]="11",妹红按住1就可以打印出来,只按了1次按钮
s[1,1]="1",妹红按住1就可以打印出来,只按了1次按钮
s[2,2]="0",妹红按住0就可以打印出来,只按了1次按钮
共有4个子串符合要求。

备注:

对于20%的样例,


对于40%的样例,


对于60%的样例,


对于100%的样例,

这个题目不能直接进行尺取

要处理一下,把他变成没有连续的就可以进行尺取了,

尺取的权值就是ans+=a[l].sum*a[r].sum;

其中m=1的时候要特判

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
struct node{
    char num;
    ll sum;
}a[maxn];
char str[maxn];
int main(){
    int n,m;
    cin>>n>>m;
    scanf("%s",str+1);
    a[1].num=str[1];
    a[1].sum=1;
    int cnt=1;
    for(int i=2;i<=n;i++){
        if(str[i]==a[cnt].num){
            a[cnt].sum++;
        }
        else{
            cnt++;
            a[cnt].num=str[i];
            a[cnt].sum=1;
        }
    }
    if(m==1){
        ll ans=0;
        for(int i=1;i<=cnt;i++){
            ans+=(a[i].sum*(a[i].sum+1))/2;
        }
        cout<<ans<<endl;
        return 0; 
    }
    int l=1,r=0;
    int p=0;
    ll ans=0;
    while(1){
        while(r<=cnt&&p<m){
            r++;
            p++;    
        }
        if(p<m){//要先判断break,在加权值
            break;
        }
        ans+=1ll*a[l].sum*a[r].sum;
        p--; 
        l++;
    }
    cout<<ans<<endl;
}
 

其实这个没有必要尺取的

思路:先统计出每段1和0的个数,如果k等于1的话,那么对于每一段就是1 + 2 + 3 + ....,求和公式,否则就是i就是从第k项开始,看第i项与第i-k项乘起来,具体看代码

#include <iostream>
#include <queue>
using namespace std;

typedef long long LL;

LL n,k;

int main()
{
    string str;
    cin >> n >> k;
    cin >> str;
    vector<int>v;
    for(int i = 0;i < n;i ++){
        int cnt = 0;
        int j = i;
        for(j = i;j < n;j ++){
            if(str[j] == str[i]){
                cnt ++;
            }else{
                break;
            }
        }
        i = j - 1;
        v.push_back(cnt);
    }
    LL res = 0;

    if(k == 1){

        for(auto &x : v){
            res += 1ll*(x + 1)* x / 2;
        }

    }else{
        k --;
        for(int i = k;i < v.size();i ++)
        {
             res += 1ll*v[i] * v[i - k] ;
        }

    }
    cout << res << endl;

    return 0;
}
原文地址:https://www.cnblogs.com/lipu123/p/14022382.html