首页 > 试题广场 >

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

[编程题]小红的01子序列构造(easy)
  • 热度指数:8227 时间限制: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)

我们将使用拉马努金瞪眼法解决这一题

注意到:题目说了是双指针

我们将使用 l r 两个指针来指向这个字符串的不同地方,其中 r 跑在前面l 跟在后面
在一开始,当然可以得知 r 的位置是 0 还是 1,这样可以很轻松得知r 向前跑一步,当前 01 字符串增加了多少次。
如果当前 01 字符串出现次数太多,则 l 进一步,这样就很轻松的可以得知当前 01 字符串减少了多少次。
直到 r 跑出界,或者当前出现次数恰好等于 k,双指针结束

证明:
为什么用双指针能行,假设题目的答案在这一段,如果当前的,就有两种情况

一是当前出现次数,则 r 继续向前

二是当前出现次数,则 l 向前。由于 r 是小于 R 的,如果 r 这一步走了之后,,那么当前出现次数 now 一定大于等于 kl 一定小于等于 L,如果 l 向前走了,now 就会变小
,也就是说,答案就出来了

注意到,代码要写成这样:

void solve()
{
    ll n = q_;
    ll k = q_;
    string num;
    cin >> num;

    ll now = 0, cnt_1 = 0, cnt_0 = 0, l = -1, r = -1;
    while (r+1 < n)
    {
        r++;
        (num[r] - '0') ? (cnt_1++, now += cnt_0) : (cnt_0++);
        while (now > k)
        {
            l++;
            (num[l] - '0') ? (cnt_1--) : (cnt_0--, now -= cnt_1);
        }
        if (now == k)
        {
            cout << l+2 << ' ' << r+1 << endl;
            return;
        }
    }
    cout << -1 << endl;
    return;
}

int main()
{
    int t = 1;
    while (t--)
    {
        solve();
    }

    return 0;
}


/*
⡀⠎⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣄⠃⠈⣶⡛⠿⠭⣉⠛⠿⡿⠛⠉⣀⣠⣤⣭⡏⠴⢀⣴⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣷⣱⣬⠛⠉⠀⠀⢠⠀⠀⠀⢀⣀⠀⠉⠿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠈⡿
⠀⠀⠀⠀⠀⠀⠀⢀⢿⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⡏⠀⠀⠀⠀⠈⠳⠀⠀⠀⠻⣿⣿⣿⣿⣿⣿⠋⠀⣇⠀⠀⠀⠀⠀⠀⠀⠀⠈
⠀⠀⠀⠀⠀⠀⠀⣸⠀⣿⣿⣿⣿⠟⠀⠀⠀⠂⠀⠀⢠⠀⠀⠀⠀⠀⠀⠀⠈⡀⠀⠀⠀⠻⣿⣿⣿⣿⣷⡀⠘
⠀⠀⠀⠀⠀⠀⠀⣧⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣄⣧
⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⣾⠀⠀⠀⠀⠀⠀⠀⠀⠀⢧⠀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⣆
⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⢂⠻⣿⣿⣿⣿⣿⣄
⠀⠀⠀⠀⠀⣿⣿⣿⣿⣹⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⠀⠀⠀⠀⠀⡄⠈⢿⣿⣿⣿⣿⣆
⠀⠀⠀⠀⣿⣿⣿⣿⠁⡇⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠐⠸⠀⠀⠻⣿⣿⣿⣆⢦
⠀⠀⢠⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⣼⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡏⣧⠀⠀⠀⠀⠐⣇⠀⠀⠙⣿⣿⣿⡄⠙⣄
⠀⣴⣿⣿⣿⣿⠏⠀⢸⠀⠀⠀⠀⠀⠀⡿⢿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣃⣈⣦⠀⠀⠀⠀⢹⠀⠀⠀⠸⣿⣿⣿⠀⠀⠳⣀
⠋⣸⣿⣿⣿⡟⠀⠀⠀⡆⠀⠀⠀⠀⠀⡏⠙⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⢠⠀⠀⠀⢧⠀⠀⠀⠀⡇⠀⠀⠀⠘⣿⣿⣷⠀⠀⠘
⠀⣿⣿⣿⢩⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⣀⠀⢱⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠂⢀⣴⣶⣿⣿⡀⠀⠀⢻⠀⠀⠀⠀⠹⣿⣿⡄
⢸⣿⣿⠃⠈⠀⠀⢸⠀⣿⣆⠀⠀⠀⠀⣿⣿⣿⠷⠘⡀⠀⠀⠀⠀⠀⠀⢠⢹⡀⠈⡿⠻⣿⣛⢿⣿⣷⡀⠈⠀⠀⠀⠀⠀⢻⣿⣿
⣿⣿⣿⠀⠀⠀⠀⢸⠀⡇⣼⣄⠀⠀⠀⢻⣿⡄⠑⠑⣿⡀⠀⠀⠀⢀⠀⠂⠇⠀⠀⠖⠛⢿⣿⣿⣌⢿⣿⣿⡆⠀⠀⠀⠀⠀⣿⣿⡀
⣿⣿⡇⠀⠀⠀⠀⢸⠀⣾⣿⣿⡷⠿⣷⣤⣿⣿⡄⠀⠀⠀⠑⠤⡀⠀⠃⠀⠀⠀⠀⣿⣶⣿⣿⣿⣿⣆⠙⣿⣧⠀⠀⠀⠀⠀⣿⣿⡇
⣿⣿⠁⠀⠀⠀⠀⠘⣾⣿⣿⠁⣴⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠸⡏⠙⣿⠉⠻⣿⠀⠀⣿⠀⠀⠀⣄⠀⣿⢸⣷
⣿⣿⡇⠀⠀⠀⠀⠀⣿⣿⠁⠀⣿⣿⠋⣿⠏⠙⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⢀⢻⠀⠀⢀⡟⢀⣿⣸⢃⠟
⣿⣿⣿⠀⡄⠀⠀⠀⠘⠻⡄⠀⢹⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠀⢀⣿⠃⣿⣿⡗⠁
⣧⣿⣿⣧⢹⡀⠀⠀⠀⠱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⣴⣿⣿⣾⣿⣿⣿
⢿⠘⣿⣿⣿⣿⣤⠀⠢⡀⠱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣵⣿⣿⣿⣿⣿⣿⣿⣿⣷
⠀⠉⣿⣿⣿⡿⣿⠻⣷⣬⣓⣬⣄⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠉⠈⠈⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⠃⠼⢉⣿⣿⣿⣿⣿⣿⣿
⠀⠀⣿⣿⣿⣷⠀⠀⠀⠘⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⡏⠀⠀⢸⠀⢻⢿⣿⣿⡏⣿
⠀⢸⣿⣿⣿⣿⠀⠀⠀⠀⢻⣿⣿⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⠀⠀⠀⢸⠀⠀⢸⣿⣿⠘⡀
⢦⡿⣿⣿⣿⢿⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣶⣶⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠘⡄⠀⠈⣿⣿⡄⠱
⣴⠛⣾⣿⣿⢸⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⡄⠀⠀⠀⠀⠀⠀⠀⣯⠛⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⣇⠀⠀⣿⣿⣿
⠿⠀⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠟⠰⡾⠃⠀⠀⠀⠀⠀⠀⠀⠙⡟⠀⢻⣿⣿⣿⣿⣿⡆⠀⠀⠀⠸⠀⠀⠸⣿⣿⣷
⠆⢳⣿⣿⡇⠀⠀⠀⠀⠀⠀⣿⣿⣿⠛⠿⠿⢿⡟⠀⠀⠉⠦⣀⡤⢶⠀⠖⠲⠶⠊⠀⠀⠀⢻⡛⠛⠛⣿⣿⠀⠀⠀⠀⠃⠀⠀⢿⣿⣿
*/
编辑于 2025-12-29 00:43:53 回复(2)
id不对
发表于 2025-03-25 18:03:35 回复(0)
枚举左端点然后二分就行了,因为右端点越往右满足的子序列数量单调不减,然后后缀算一下子序列的数量,二分ck的时候减一下就行了
ll dp[N],cnt1[N],cnt0[N];
ll ck(int l,int r){
    return dp[l]-dp[r+1]-((cnt0[l]-cnt0[r+1])*cnt1[r+1]);
}
void solve(){
    ll n,k;
    cin>>n>>k;
    string s;cin>>s;
    s='$'+s;
    for(int i=n;i>=1;i--){
        if(s[i]=='1')dp[i]=dp[i+1];
        else dp[i]=dp[i+1]+cnt1[i+1];
        cnt1[i]=cnt1[i+1]+(s[i]=='1');
        cnt0[i]=cnt0[i+1]+(s[i]=='0');
    }
    for(int i=1;i<=n;i++){
        int L=i+1,R=n,ans=-1;
        while(L<=R){
            int mid=(L+R)>>1;
            if(ck(i,mid)<=k){
                ans=mid;
                L=mid+1;
            }else{
                R=mid-1;
            }
        }
        if(ans!=-1){
            if(ck(i,ans)==k){
                cout<<i<<" "<<ans<<'\n';
                return ;
            }
        }
    }cout<<-1<<'\n';
}   


发表于 2025-12-29 22:36:03 回复(0)

注意到字串变长时,其中的 01 子序列数量单调不减,故可以用二分。

(注释由 AI 生成,但是 AI 太笨了不会讲原理,基本只是在解释每一步做了什么)

# 导入operator模块的le方法(注:当前代码中未实际使用该方法,属于冗余导入)
from operator import le
# 读取输入的n和k:n为字符串长度,k为目标匹配值
# strip()去除首尾空白,split()按空格分割,map(int, ...)转换为整数类型
n, k = map(int, input().strip().split())
# 读取输入的二进制字符串s(仅包含'0'和'1')
s = input().strip()
# 前缀数组:pre_0[i] 表示字符串s的前i个字符(s[0..i-1])中'0'的个数
# 长度为n+1,方便处理边界情况(前缀和常用初始化方式)
pre_0 = [0] * (n + 1) 
# 后缀数组:suf_1[j] 表示字符串s从j位置开始到末尾(s[j..n-1])中'1'的个数
suf_1 = [0] * n 
# 后缀数组:suf_01[j] 表示字符串s从j位置开始到末尾,每个'0'对应的后续'1'的个数之和
# 即对于s[j..n-1]中的每个'0',累加其右侧(包括自身之后)的'1'数量,最终求和
suf_01 = [0] * n 
# 初始化suf_1的最后一个元素(最右侧字符):如果是'1',则后缀1的个数为1
if s[-1] == '1':
    suf_1[-1] = 1
# 循环遍历,同时构建前缀数组pre_0和后缀数组suf_1、suf_01
for i in range(n):
    # 构建pre_0:继承前一个位置的前缀0个数(pre_0[i-1])
    # 注:i=0时,pre_0[i-1] = pre_0[-1],即pre_0数组的最后一个元素(初始为0)
    pre_0[i] = pre_0[i - 1]
    # 如果当前字符是'0',前缀0的个数加1
    if s[i] == '0':
        pre_0[i] += 1

    # 当i>0时,反向遍历构建后缀数组(j = n-1-i 从倒数第二个字符向前遍历)
    if i > 0:
        # 计算反向遍历的索引j(从后往前第i+1个位置)
        j = n - 1 - i
        # 构建suf_1:继承j+1位置的后缀1个数(右侧的后缀1总数)
        suf_1[j] = suf_1[j + 1]
        # 如果当前字符是'1',后缀1的个数加1
        if s[j] == '1':
            suf_1[j] += 1

        # 构建suf_01:继承j+1位置的suf_01值(右侧的0对应1的累计和)
        suf_01[j] = suf_01[j + 1]
        # 如果当前字符是'0',则累加当前位置右侧的1的个数(suf_1[j])到suf_01[j]
        if s[j] == '0':
            suf_01[j] += suf_1[j]
# 自定义二分查找函数:在区间[i, n-1]中查找符合target条件的最大索引j
# 参数i:查找的左边界起始位置;target:目标匹配值
def bisect(i, target):
    # 二分查找的左边界(起始为i)和右边界(末尾为n-1)
    left = i 
    right = n - 1
    # 二分查找循环:当左边界不超过右边界时继续
    while left <= right:
        # 计算中间索引mid(等价于(left + right) // 2,位运算更高效)
        mid = left + right >> 1
        # 计算决策值dec:用于判断是否满足目标条件
        # 组成:suf_01[mid](mid右侧0对应1的累计和) + 区间[i, mid-1]内0的个数 * suf_1[mid](mid右侧1的个数)
        dec = suf_01[mid] + (pre_0[mid - 1] - pre_0[i - 1]) * suf_1[mid]
        # 如果dec大于等于目标值,说明需要向右查找更大的索引
        if dec >= target:
            left = mid + 1
        # 否则向左查找
        else:
            right = mid - 1

    # 循环结束后,计算右边界right对应的dec值(验证是否符合目标)
    dec = suf_01[right] + (pre_0[right - 1] - pre_0[i - 1]) * suf_1[right]
    # 如果dec等于target,返回right(找到符合条件的索引);否则返回特殊值-114514(标记未找到)
    return right if dec == target else -114514 
# 核心求解函数:查找满足条件的字符串区间[i+1, j](题目要求输出1-based索引)
def solve():
    # 遍历每个可能的起始位置i(0-based,对应字符串s的第i个字符)
    for i in range(n):
        # 情况1:如果从i位置到末尾的suf_01值恰好等于k,直接返回区间[i+1, n](1-based)
        if suf_01[i] == k:
            return f'{i + 1} {n}'
        # 情况2:如果从i位置到末尾的suf_01值小于k,说明不存在符合条件的区间,返回'-1'
        if suf_01[i] < k:
            return '-1'
        # 情况3:计算目标值target = 当前suf_01[i] - k,用于二分查找
        target = suf_01[i] - k 
        # 调用二分查找函数,查找符合target条件的j
        j = bisect(i, target)
        # 如果j返回特殊值(未找到),继续遍历下一个i
        if j < 0:
            continue 
        # 找到符合条件的j,返回区间[i+1, j](1-based索引)
        return f'{i + 1} {j}'
# 调用求解函数并打印结果
print(solve())

# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⠶⠟⠛⠛⠛⠛⠷⡶⠶⠿⠛⠷⠶⣦⣤⡀
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠶⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠶⣄
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢶⡀
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⠫⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⠀⠀⠉⢷⡀
# ⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠒⡀⠀⠀⠀⠙⣦
# ⠀⠀⠀⠀⣠⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢆⠀⠀⠀⠘⣧
# ⠀⠀⠀⣴⠁⠀⢀⠤⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠈⢿⡀
# ⠀⠀⡾⠀⣠⢾⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡆⠀⠀⠀⠹⣆
# ⠀⢸⢁⠞⠀⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣿⠀⠀⠀⠀⠀⠀⢰⣿⠑⠢⣄⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠘⣆
# ⠀⠘⠃⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠠⠋⢀⢏⢿⠀⠀⠀⠀⠀⢀⣿⣌⣆⠀⠀⣏⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠈⠀⠀⢄⠀⠀⢹⡀
# ⠀⠀⠀⠀⢀⡇⠀⠀⠀⠀⠀⠀⢠⠀⠀⡟⠟⢞⣇⠀⠀⠀⠀⢿⠟⠀⠙⣆⠀⢹⢦⡀⠀⠘⠀⠀⠀⠀⠀⠀⣄⠀⠀⠀⢳⡀⠀⣇
# ⠀⠀⠀⣤⠋⠀⠀⠀⠀⠀⠀⢀⡿⡄⢸⠙⠀⠀⠻⣆⢠⣄⠀⠀⣧⠀⠀⠀⠛⢦⣷⠙⢶⣄⠀⠀⠀⠀⠀⠀⠹⡀⠀⢠⣼⠻⡀⡟
# ⢀⣴⠟⠀⠀⠀⣀⠞⠀⠀⠀⣼⢋⠈⠻⠀⢀⣪⡶⠀⠛⠃⠉⠛⠻⣬⣑⣀⣀⣀⣤⣶⣷⣸⠀⠀⠀⠀⠠⠀⠀⠙⣄⠀⣿⠀⠛
# ⠀⠉⠛⠛⡿⠁⠀⠀⣄⠀⠀⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣿⡿⠿⡿⠀⠀⠀⠀⠀⡾⠓⠶⠶⠋⠘⣦
# ⠀⠀⢀⠟⠀⠀⠀⣼⣿⣦⡀⠹⡀⠀⠙⠁⠀⠀⠒⠶⠒⠲⠤⠴⠀⠀⠀⠀⠁⠀⠀⠀⣾⠀⠀⠀⠀⠀⡾⠉⢷⣳⢄⠀⠀⠈⠳⣄
# ⠀⠀⡿⠀⠀⠀⣠⣿⣿⢿⣿⠉⠉⠎⢀⠀⡎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠀⠃⢸⠀⣿⡤⣶⠁⠀⢠⣿⣿⠛⢀⣿⡇⡿⠶⣤⣤⣤⠟
# ⠀⠀⡇⠀⡴⢋⣼⠗⣉⢯⣿⣷⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⠀⣀⣾⠉⠉⠀⣠⣿⣿⣧⣿
# ⠀⠀⠹⠟⠀⣧⡴⣻⠃⣾⣿⣿⣋⠛⢶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣛⣿⣿⣍⣴⣭⣿⡻⣿⣿⣿⣿⣞⣦
# ⠀⠀⠀⠀⠀⣾⣿⠃⢰⣿⠟⠐⣿⢏⣿⣿⣝⣿⣿⣿⠿⠶⠶⠶⠶⠶⠶⣿⠟⣩⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣷⣿⣦⣤
# ⠀⠀⠀⠀⠀⠠⣧⡀⣿⠁⢀⠋⢠⠋⠀⠙⠀⠉⠁⠀⠀⠀⠀⠀⠀⣴⣻⣿⣿⠦⣠⠛⠋⠁⣿⣿⠋⠻⣿⣿⣿⠉⠛⠿⠿⠛⠋
# ⠀⠀⠀⠀⠀⠀⠀⠀⣿⣾⢻⢠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⣿⡿⣵⠛⠀⠀⠀⠀⠁⠀⠀⠀⣿⠟
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣏⡟⡟
#
发表于 2025-12-29 14:39:58 回复(0)
#include <bits/stdc++.h>
using namespace std;
using ll=long long;

int main() {
    ll n,k;cin >> n >> k;
    string s;cin >> s;
    ll now;
    ll cnt0=0,cnt1=0;
    ll l=0,r=0;
    if(s[0]=='0') cnt0++;
    else if(s[0]=='1') cnt1++;
    while(now!=k)
    {
        if(now>k)
        {
            l++;
            if(s[l-1]=='0')
            {
                cnt0--;
                now-=cnt1;
            }
            else if(s[l-1]=='1')
            {
                cnt1--;
            }
        }
        else if(now<k)
        {
            r++;
            if(s[r]=='0')
            {
                cnt0++;
            }
            else if(s[r]=='1')
            {
                cnt1++;
                now+=cnt0;
            }
        }
        if(r==n||l==n)
        {
            cout << -1;
            return 0;
        }
    }
    cout << l+1 <<' '<< r+1;
}
/*
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⡀⣀⣠⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⡀⢀⣴⣾⣷⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣾⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⠿⠛⠛⠉⠉⠉⠉⠉⠉⠛⠻⠿⣿⣿⣿⣿⣿⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⡿⠿⠛⠉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠿⣿⣿⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣀⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⣰⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣠⣾⣿⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣶⣄⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣻⣿⣿⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢹⣿⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⠁⠈⢢⡀⠀⠀⠀⢸⡇⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⡟⠒⢦⡀⠀⠀⠀
⠀⠀⣠⣤⣤⣼⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡇⠀⠀⠀⠉⢢⣄⠀⠀⢿⠊⠳⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣷⡄⠀⢷⠀⠀⠀
⠀⢰⠇⠀⣰⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⡌⣹⠗⠦⣬⣇⠀⠉⢢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⡀⢸⡄⠀⠀
⠀⡟⠀⣼⣯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣆⢹⡀⠀⠀⠀⠉⠁⠀⠀⢀⣀⡁⠀⠀⠉⠳⢴⡆⠀⠀⠀⠀⠀⠀⢹⣧⠈⡇⠀⠀
⠀⡇⠀⠀⢻⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣾⠻⠉⠛⠂⠀⠀⠀⠀⠀⠀⠻⠿⣿⣿⣿⣶⣦⡀⠛⣇⠀⠀⠀⠀⠀⣈⣿⠀⡇⠀⠀
⢸⡇⠀⠀⢠⣿⣷⣦⣀⡸⣷⣦⣶⡂⠉⠉⠉⢁⣤⣶⡶⠀⠀⠀⣀⣀⡴⠀⠀⠀⠀⠀⠀⠈⠉⠉⠁⠀⡟⢀⣴⣟⣰⣾⣿⣏⣠⠇⠀⠀
⠈⡇⠀⠀⢸⣿⠁⠉⣿⠛⠛⠃⡇⠀⠀⢠⣶⣿⡿⠛⠁⠀⠀⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⢿⠟⠿⢿⡏⠀⠘⣿⡀⠀⠀⠀
⠀⢷⣀⣀⣿⠇⠀⠀⢿⡇⠀⢀⢱⡀⠀⠛⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠀⠀⢸⠇⠀⠀⢹⣿⣄⠀⠀
⠀⠀⣉⣿⡏⠀⠀⠀⠀⠀⠀⢸⣇⣳⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⣿⠃⠀⠀⠀⠀⠀⠀⣿⠈⢧⠀
⠀⠘⣿⣿⠁⠀⠀⠀⠀⠀⠀⠘⣿⡛⣶⠀⠀⣠⠔⠒⠛⠒⠦⡀⠀⠀⠀⠀⣠⡤⠶⠤⢤⣀⠀⠀⠀⢀⣏⡄⠀⠀⠀⠀⠀⡀⣿⡆⠈⣧
⣠⡾⠛⣿⣿⣧⠀⠀⠀⠀⢸⣿⠾⢿⡿⠀⣰⠃⠀⠀⠀⠀⠀⢹⡄⠀⠀⡼⠁⠀⠀⠀⠀⠈⠙⣦⠀⢸⣿⡇⣾⣣⡀⠀⢰⣿⣿⣿⣤⠾
⡟⠀⠀⠻⣿⡟⢷⡄⣤⡀⠈⣿⡀⣸⠇⠀⠏⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⡇⢀⡀⠀⠀⠀⠀⢀⡟⠀⠀⠋⣿⣿⣿⡇⣠⣿⠿⠛⢷⡀⠀
⠀⠀⠀⠀⣿⣇⣨⣿⣿⣿⣦⣽⣷⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠃⠀⠙⠢⠤⠤⠴⢾⠀⠀⠀⠀⢸⣷⣿⣿⠟⠁⠀⠀⠈⣧⠀
⠀⠀⠀⠀⠈⠉⠉⠁⠈⠉⠈⢉⣿⡁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⣿⠀
*/

发表于 2025-12-29 07:42:45 回复(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)