#P2897. 第1题-小红听歌
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 36
            Accepted: 9
            Difficulty: 4
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年4月24日-阿里云(算法岗)
                              
                      
          
 
- 
                        算法标签>模拟          
 
第1题-小红听歌
问题本质
播放指针初始位置为已播放歌词个数 k0 = count(t[i] == '1')。未播放的歌词就是 s[k0+1..n]。幸运串长度为
m = Σ(cnt[i])  i=1..26
要让未播放部分正好是幸运串,必须满足
n − k = m   ⇔   k = n − m
因此,唯一可行的目标前缀长度 k* = n−m。每次操作将 k ±1,最少操作次数即为
| k0 − k* |
算法思路
- 读入 
cnt[1..26]并计算m = Σ cnt[i]。 - 读入 
n, s, t,统计t中1的个数k0。 - 目标前缀长度 
k* = n − m。 - 答案为 
abs(k0 − k*)。 
此处用到的主要操作是数组求和和字符串统计,时间复杂度为 O(n + 26),空间复杂度为 O(n)。
复杂度分析
- 
时间复杂度
- 统计 
cnt:O(26) - 读取并统计 
t中的1:O(n) - 其他常数级操作
总计:O(n) 
 - 统计 
 - 
空间复杂度
- 存储 
s和t:O(n) - 存储 
cnt和若干标量:O(1)
总计:O(n) 
 - 存储 
 
代码实现
Python
def main():
    cnt = list(map(int, input().split()))
    m = sum(cnt)
    n = int(input())
    s = input()
    t = input()
    k0 = t.count('1')
    kt = n - m
    print(abs(k0 - kt))
if __name__ == "__main__":
    main()
Java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(in.readLine());
        int[] cnt = new int[26];
        int m = 0;
        for (int i = 0; i < 26; i++) {
            cnt[i] = Integer.parseInt(st.nextToken());
            m += cnt[i];
        }
        int n = Integer.parseInt(in.readLine());
        String s = in.readLine();
        String t = in.readLine();
        int k0 = 0;
        for (char c : t.toCharArray()) {
            if (c == '1') k0++;
            else break;  // 保证1都在前面
        }
        int kt = n - m;
        System.out.println(Math.abs(k0 - kt));
    }
}
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    vector<int> cnt(26);
    long long m = 0;
    for (int i = 0; i < 26; i++) {
        cin >> cnt[i];
        m += cnt[i];
    }
    int n;
    cin >> n;
    string s, t;
    cin >> s >> t;
    int k0 = 0;
    for (char c : t) {
        if (c == '1') k0++;
        else break;  // t 中所有1在前
    }
    int kt = n - m;
    cout << abs(k0 - kt) << "\n";
    return 0;
}
        题目内容
小红正在听歌,屏幕上同时展示着歌词和对应的播放进度条。设:
- 字符串s表示歌曲的完整歌词,下标从1开始,且仅由小写字母构成;
 - 字符串t表示歌词的播放进度条,下标从1开始,且仅由字符0和1组成,其中:
 - 当ti=0时,表示第i个歌词尚未播放;
 - 当ti=1时,表示第i个歌词已经播放。
 
小红每次可以操作快进或回退一个歌词(即将播放指针向右或向左移动一个位置),数据初始时和操 作过程均保证已经播放的歌词是s的一个前缀(可为空串)。
她的目标是:以尽可能少的操作次数,使得字符串s中未播放状态的歌词是"幸运串"。
请你计算,为了达到该目标,至少需要多少次操作?(数据保证可以在有限次内完成操作目标)
【幸运串】每种字母出现的次数为指定的次数,可为空串,具体可查看输入描述。
输入描述
输入第一行包含26个整数,表示一个幸运串每种字母出现的次数, cnt1,cnt2,⋅,cnt26(0≦cnti≦n)对应a,b,...,z的出现次数。
输入第二行一个整数n(1≦n≤2×105),表示歌词的长度。
输入第三行包含一个字符串s,表示歌曲的完整歌词,仅由小写字母构成。
输入第四行包含一个字符串t,表示歌词的播放进度条,仅由字符0和1组成。保证字符串中全部的1都位于全部的0之前(符合常识逻辑)。
输出描述
输出一个整数,表示使得未播放歌词构成幸运串所需要的最少操作次数。
样例1
输入
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
8
acabccab
11111000
输出
1
说明
只需要快进一次,即向右移动一次,使得a和b未播放的歌词都剩余一次。
样例2
输入
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
8
acabccab
11111100
输出
0
说明
不用操作,此时a和b未播放的歌词都剩余一次。