首页 > 试题广场 >

小红的01子序列构造(easy)

[编程题]小红的01子序列构造(easy)
  • 热度指数:6161 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}给定一个仅由字符 \tt 0,1 组成的字符串 s,长度为 n。小红想找到一个闭区间 [l,r] 使得在子串 s_{l..r} 中,恰好存在 k 个严格等于 01子序列(即选取下标 i<j,满足 s_i=\texttt{0},\ s_j=\texttt{1})。
\hspace{15pt}请你输出任意一个满足条件的区间;若不存在,则输出 -1

【名词解释】
\hspace{15pt}子序列:从字符串中删除任意个(可为零)字符后得到的字符串,保留剩余字符原有相对顺序。

输入描述:
\hspace{15pt}第一行输入两个整数 n,k\left(1\leqq n\leqq 2\times10^{5};\ 1\leqq k\leqq 10^{10}\right)——字符串长度与目标子序列数量。 
\hspace{15pt}第二行输入一个长度为 n 的 01 串 s(下标从 1 开始)。


输出描述:
\hspace{15pt}若不存在满足要求的区间,输出单独一行-1;否则输出两个整数 l,r\left(1\leqq l\leqq r\leqq n\right) 表示区间端点(输出任意一组均可)。
示例1

输入

4 2
0011

输出

1 3

说明

子串 s_{1..3}=\texttt{ 内的 01 子序列共有 2 个:s_1s_3s_2s_3
示例2

输入

4 2
1110

输出

-1
双指针的使用:
通过不断移动右指针 r 来扩展区间,当 01 子序列的数量 num 超过 k 时,移动左指针 l 来收缩区间,以保证 num 尽可能接近 k。若最终没有找到满足 num = k 的区间,输出 -1
#include <iostream>
#include <string>
using namespace std;

int main() {
    int n;
    long long k;
    cin >> n >> k;
    string s;
    cin >> s;

    int l = 0;
    int r = 0;
    int num0 = 0;
    int num1 = 0;
    long long num = 0;
    for (int i = 0; i < n; i++) {
        if (num == k) {
            cout << l + 1 << ' ' << r + 1 << endl;
            return 0;
        }
        // 扩展
        if (num < k) {
            r = i;
            if (s[r] == '0') {
                num0++;
            } else {
                num1++;
                num += num0;
            }
        }
        // 收缩
        if (num > k) {
            while (num > k) {
                if (s[l] == '0') {
                    num0--;
                    num -= num1;
                } else {
                    num1--;
                }
                l++;
            }
        }
    }
    cout << -1 << endl;
    return 0;
}    


发表于 2025-04-09 13:31:30 回复(0)
id不对
发表于 2025-03-25 18:03:35 回复(0)
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        try {
            long n = in.nextLong(); // 改用 long
            long k = in.nextLong();
            in.nextLine();
            String s = in.nextLine();

            long left = 0;
            long num0 = 0; // 当前窗口内的 '0' 的数量
            long num1 = 0; // 当前窗口内的 '1' 的数量
            long sum = 0;  // 当前窗口内的 "01" 子序列数量

            for (long right = 0; right < n; right++) {
                if (s.charAt((int) right) == '0') {
                    num0++;
                } else {
                    sum += num0; // 当前 '1' 可以与前面所有 '0' 配对
                    num1++;
                }

                // 收缩窗口,使 sum <= k
                while (sum > k) {
                    if (s.charAt((int) left) == '0') {
                        num0--;
                        sum -= num1; // 移除 '0' 会减少它后面 '1' 的配对数量
                    } else {
                        num1--; // 移除 '1' 不影响 sum
                    }
                    left++;
                }

                if (sum == k) {
                    System.out.println((left + 1) + " " + (right + 1)); // 1-based 输出
                    return;
                }
            }
            System.out.println("-1");
        } catch (InputMismatchException e) {
            System.out.println("输入不是有效的整数!");
        }
    }
}
发表于 2025-09-10 19:46:08 回复(0)
接收控制台传过来的字符串长度和目标子序列数量,注意子序列数量可能超int值,所以需用long来接收。
保存控制台过来的字符串,用大小为2的数组分别存储0、1的数量。
定义左右指针left和right开始滑动窗口寻找符合题意的区间,
我们只需要找一个区间,当找到符合条件的区间时,用resultleft、resultright保存区间左右边界,直接返回即可。
用right滑动窗口,只有在右边界字符为1时,才有可能得到结果,当遍历到1时,res += (left, right)区间中0的个数,
当res大于目标值时,需要持续滑动窗口left,left == ‘0’时,res -= 1的数量,直到res <= target,退出循环。
此时判断res 是否等于target,若等于,说明找到了满足题意的区间,记录区间左右边界并返回、输出。
若遍历完集合还未找到,返回-1。
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNext()) { // 注意 while 处理多个 case
            int n = in.nextInt();
            Long k = in.nextLong();
            char[] chars = in.next().toCharArray();
            int[] zeroAndOne = new int[2];
            int left = 0, right = 0;
            long res = 0;
            int resultleft = 0, resultright = 0;
            for (int i = 0; i < chars.length; i++) {
                if (chars[i] == '1') {
                    res += zeroAndOne[0];
                    zeroAndOne[1]++;
                    while (res > k) {
                        if (chars[left] == '0') {
                            res -= zeroAndOne[1];
                            zeroAndOne[0]--;
                        } else if (chars[left] == '1') {
                            zeroAndOne[1]--;
                        }
                        left++;
                    }
                    if (res == k) {
                        resultleft = left + 1;
                        resultright = i + 1;
                        break;
                    }
                } else {
                    zeroAndOne[0]++;
                }
            }
            if (resultleft != 0 && resultright != 0) {
                System.out.println(resultleft + " " + resultright);
            } else System.out.println(-1);
        }
    }
}

发表于 2025-07-22 17:12:47 回复(0)
ls = list(map(int,input().split()))
s = input()
n = ls[0]
k = ls[1]
ex = -1
if n<k+1:
    print(-1)
else:
    for i in range(k+1,n+1):
        for j in range(n-i+1):
            in_str = s[j:j+i]
            if in_str.count('0') < k:
                print('-1')
            else:
                for m in range(len(in_str)-1,0,-1):
                    if in_str[m] == '1':
                        inn_str = in_str[:m]
                        if inn_str.count('0') >= k:
                            print(f'{j+1} {j+i}')
                            ex = 0
                            break
            break
        break
    if ex == -1:
        print(-1)
发表于 2025-04-19 23:43:10 回复(0)
#参考双指针思路
n, k = map(int, input().split())
s = input().strip()

if n == 0:
    print(-1)
    exit()

cnt0 = 0
cnt1 = 0
l = 0
r = 0

# 初始化第一个字符
if s[0] == '0':
    cnt0 += 1
elif s[0] == '1':
    cnt1 += 1

num = 0
result = None

while l < n and r < n:
    if num == k:
        result = (l + 1, r + 1)
        break
    if num < k:
        # 移动右指针
        if r + 1 < n:
            r += 1
            current_char = s[r]
            if current_char == '0':
                cnt0 += 1
            else:
                num += cnt0
                cnt1 += 1
        else:
            # 无法移动右指针时,尝试移动左指针
            current_char = s[l]
            if current_char == '0':
                num -= cnt1
                cnt0 -= 1
            else:
                cnt1 -= 1
            l += 1
    else:
        # 移动左指针
        current_char = s[l]
        if current_char == '0':
            num -= cnt1
            cnt0 -= 1
        else:
            cnt1 -= 1
        l += 1

# 检查退出循环后是否满足条件
if result is None and num == k and l <= r < n:
    result = (l + 1, r + 1)

if result:
    print(result[0], result[1])
else:
    print(-1)

发表于 2025-04-14 15:07:30 回复(0)
//超时笨蛋
n, k = map(int, input().split())
s = input()
ans =[]
for i in range(len(s)):
    for j in range(i, len(s)):
        t=0
        t2 = 0
        st = s[i:j]
        for q in st:
            if q == '0':
                t+=1
            else:
                t2 = t2 + t
        if t2 == k:
            ans = [i+1, j]
            break
        elif t2 > k:
            break
        else:
            continue
    if ans != []:
        break
if ans == []:
    print(-1)
else:
    print(*ans)
       
发表于 2025-04-13 22:46:47 回复(0)
n,k=map(int,input().split())
s=input()
cnt0,cnt1=0,0
l,r=0,0
if s[0]=='0':cnt0+=1
if s[0]=='1':cnt1+=1
num=0
while l<n and r<n:
    if num==k:
        print(l+1,r+1)
        break
    elif num<k and r<n-1:
        r+=1
        if s[r]=='0':
            cnt0+=1
        else:
            num+=cnt0
            cnt1+=1
    elif num<k and r==n-1:
        print(-1)
        break
    else:
        if s[l]=='0':
            num-=cnt1
            cnt0-=1
        else:
            cnt1-=1
        l+=1
发表于 2025-03-31 14:48:27 回复(0)
//牛蛙
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        Long k = in.nextLong();
        in.nextLine();
        String a = in.nextLine();
        //有俩种方法 第一种是先构建窗口 如果窗口内满足就输出 否则就右移
        //第二种是直接统计每个1的位置贡献了多少个0  计算哪个区间的1能够达到要求
        //使用第二种方法
        int l = 0,r=0,num0=0,num1=0;
        long num=0;
        boolean NO = true;
        for(int i = 0;i<n;i++){

            if (num == k) {
                System.out.println((l+1) + " " + (r+1));
                return;
            }
            if(num<k){
                r = i;
                if(a.charAt(r)=='1'){
                    num1++;
                    num = num + num0;
                }else{
                    num0++;
                }
            }
            if(num>k){//移多了 需要左区间右移l++
                while(num>k){
                    if(a.charAt(l)=='1'){
                        num1--;
                    }else{
                        num0--;
                        num = num-num1;
                    }
                    l++;
                }

            }

        }
        if(NO){
            System.out.println(-1);
        }

    }
}

发表于 2025-03-28 21:53:42 回复(0)