首页 > 试题广场 >

小红的排列构造②

[编程题]小红的排列构造②
  • 热度指数:4103 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}小红定义一个仅由 \texttt{0}\texttt{1} 两个字符构成的字符串 s 与一个长度为 n 的数组 p匹配,当且仅当满足下列两点:
{\hspace{20pt}}_\texttt{1.}\,s_i=\texttt{1},则数组 \{p_1,p_2,\dots,p_i\} 恰好构成一个排列;
{\hspace{20pt}}_\texttt{2.}\,s_i=\texttt{0},则数组 \{p_1,p_2,\dots,p_i\} 无法构成一个排列。

\hspace{15pt}现在小红给出了一个长度为 n 的字符串 s,请你构造一个长度为 n 的排列 p 使得 sp 匹配;如果不存在这样的排列,请输出 -1

\hspace{15pt}【名词解释】
\hspace{23pt}\bullet\,排列排列是由 1\sim nn 个整数按任意顺序组成的数组,其中每个整数恰好出现一次。

输入描述:
\hspace{15pt}第一行输入一个整数 n\left(1\leqq n\leqq 10^5\right) 表示字符串及排列的长度。 
\hspace{15pt}第二行输入一个长度为 n,仅由 \texttt{0}\texttt{1} 构成的字符串 s


输出描述:
\hspace{15pt}如果不存在满足条件的排列,直接输出 -1;否则,在一行上输出 n 个整数 p_1,p_2,\dots,p_n 表示你构造出的排列。 
\hspace{15pt}如果存在多个满足条件的排列,输出任意一个均可,系统将自动判定其正确性。请注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
示例1

输入

3
001

输出

3 1 2

说明

\hspace{15pt}对于这个样例,
\hspace{23pt}\bullet\,由于 s_0 = {\tt 0},排列的前一项元素无法构成一个排列;
\hspace{23pt}\bullet\,由于 s_1 = {\tt 0},排列的前两项元素无法构成一个排列;
\hspace{23pt}\bullet\,由于 s_2 = {\tt 1},排列的前三项元素构成一个排列;
\hspace{15pt}同时,输出 \{2,3,1\}\{3,2,1\} 等答案也都是合法的。
示例2

输入

4
1110

输出

-1

说明

在此样例中,若存在合法排列,则前三位必须依次形成排列,但第四位又要求整体不形成排列,显然不可能,因此答案为 -1
提看不懂怎么办
发表于 2025-05-21 23:10:32 回复(4)
可以有一个题解,把题说清楚可以吗?我还不想看答案
发表于 2025-07-21 11:33:47 回复(0)
解题思路:
1. 找规律,结尾是0的肯定不符合条件
2. 每个长串可以理解为多个0开始1结尾或者全1的子串
3. 如果是全部为1,这该位置直接放入对应的数字
4. 如果是0开始1结尾这种子串,0的位置填该位置后一位,1位置填首位0的位置。举例:0001 ==> 2341
代码示例:
public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String length = in.nextLine();
        String input = in.nextLine();
        resultList = new LinkedList<>();
        boolean res = getResult(input);
        if (res) {
            resultList.forEach(s->System.out.print(s + " "));
        } else {
            System.out.println(-1);
        }
    }

    static List<Integer> resultList = new LinkedList<>();
    public static boolean getResult(String str) {
        if (str.endsWith("0")) {
            return false;
        }
        Integer temp = 1;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == '0') {
                resultList.add(i + 2);
            } else {
                resultList.add(temp);
                temp = i + 2;
            }
        }
        return true;
    }


发表于 2025-03-23 21:46:23 回复(0)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(); // 读取字符串长度
        String s = sc.next();  // 读取01字符串
        sc.close(); // 关闭扫描器

        // 若字符串最后一位不是1,直接输出-1(无法满足置换要求)
        if (s.charAt(n - 1) != '1') {
            System.out.println(-1);
            return;
        }

        int flag = 0; // 标记下一个置换区间的起始位置
        int[] arr = new int[n]; // 存储置换结果的数组

        // 遍历字符串,处理每个'1'对应的置换
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '1') {
                // '0'对应的位置:值=自身索引+1(不置换)
                for (int j = flag + 1; j < i; j++) {
                    arr[j] = j + 1;
                }
                // '1'对应的位置:flag和i互换(值=对方索引+1)
                arr[flag] = i + 1;
                arr[i] = flag + 1;
                flag = i + 1; // 更新下一个置换区间起点
            }
        }

        // 输出最终置换结果
        for (int a : arr) {
            System.out.print(a + " ");
        }
    }
}

发表于 2025-10-16 19:56:10 回复(0)

以堆栈的思路来写,遍历字符串的每项,遍历到第i项则将i存入堆栈,若第i项为1则将堆栈内全部内容输出,否则不作操作
以001为例,{p1},{p1,p2}不能构成排序,而{p1,p2,p3}要构成排序,这时就可以想到将1压入栈底,将2,3先输出
以0101为例,对于前两项先输出了2 1,对于第3项,同理将3压入栈底,前两项已经构成排序,即已经包含1与2,只要p3输出的不是3,那么{p1,p2,p3}就不能构成排序,而第4项为1,这时输出堆栈中的内容,p3为4,p4为3,恰能构成排序
代码示例:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n=in.nextInt();
        String s=in.next();
        Stack<Integer> st=new Stack<Integer>();
        if(s.charAt(n-1)=='0'){
            System.out.print(-1);
            return;
        }
        for(int i=1;i<=n;i++){
            st.push(i);
            if(s.charAt(i-1)!='0'){
                while(!st.empty()) System.out.print(st.pop()+" ");
            }
        }
    }
}


发表于 2025-06-27 15:02:27 回复(0)
//D老师代码看不懂 头铁自己写 写了一下午 5小时!!!! 大家记得把输出最后末尾的空格去掉哦!!!

import java.util.ArrayList;
import java.util.Scanner;
import java.util.List;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        in.nextLine();
        String s = in.nextLine();
        if (s.charAt(s.length() - 1) == '0') {
            System.out.println(-1);
            return;
        }
        boolean onekai = false;
        int b = 0;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '0') {
                b++;
                onekai = true;
            } else {
                break;
            }
        }
        List<Integer> q = new ArrayList<>();
        int count = 0;
        if (onekai) {
            b = b + 1;
            for (int i =  b; i < n; i++) {
                if (s.charAt(i) == '1') {
                    q.add(count);
                    count = 0;
                }
                if (s.charAt(i) == '0') {
                    count++;
                }
            }
            /*
                        System.out.println("NO");
                        for (int i = 0; i < q.size(); i++) {
                            System.out.print(q.get(i));
                        }
                        System.out.println("NO");

             */

            if (b != 0) {
                System.out.print(b + " ");
                for (int i = 1; i < b ; i++) {
                    if (i == n-1) {
                        System.out.print(i);
                    } else {
                        System.out.print(i + " ");
                    }
                }
            }
            for (int i = b; i < n;) {
                for (int j : q) {
                    j++;
                    int a = i;
                    while (j-- > 0) {
                        i++;
                        if (i == n) {
                            System.out.print(1 + a + j);
                        } else {
                            System.out.print(1 + a + j + " ");
                        }
                    }
                }
            }
        } else {
            for (int i = 0; i < n; i++) {
                if (s.charAt(i) == '1') {
                    q.add(count);
                    count = 0;
                }
                if (s.charAt(i) == '0') {
                    count++;
                }
            }
            /*
                        System.out.println("NO");
                        for (int i = 0; i < q.size(); i++) {
                            System.out.print(q.get(i));
                        }
                        System.out.println("NO");

             */
            for (int i = 0; i < n;) {
                for (int j : q) {
                    j++;
                    int a = i;
                    while (j-- > 0) {
                        i++;
                        if (i == n) {
                            System.out.print(1 + a + j);
                        } else {
                            System.out.print(1 + a + j + " ");
                        }
                    }
                }
            }
        }
    }
}

发表于 2025-03-19 19:06:07 回复(0)
n, s = int(input()),input()
N = len(s)

def _solve():
    if s.endswith("0"):
        return "-1"
    oi = [-1]
    for i in range(N):
        if s[i] == "1":
            oi.append(i)
    no = len(oi)
    d = [0] * n
    for i in range(no - 1, 0, -1):
        num = oi[i] + 1
        index = oi[i - 1] + 1
        d[index] = k = num
        for j in range(index + 1, num):
            k -= 1
            d[j] = k
    return " ".join(map(str,d))

def solve():
    res = _solve()
    print(res)

solve()

发表于 2025-03-05 15:08:24 回复(0)
构造一个从1-n的顺序数组res
如果当前位置上s[i]为0,则对res中跟后一个元素调换一下位置即可
from re import template
def main():
    import sys
    data = sys.stdin.read().splitlines()
    n = int(data[0].strip())
    s = data[1].strip()
   
    if s[-1] == '0':
        print(-1)
        return
    res = [str(x) for x in range(1, n+1)]
    for i,val in enumerate(s):
        if val == "0":
            res[i+1],res[i] = res[i],res[i+1]
    print(" ".join(res))

if __name__ == '__main__':
    main()

发表于 2026-01-30 00:47:09 回复(0)
这题目到底在说什么?
发表于 2026-01-05 17:52:57 回复(0)
膜拜大神的思路,简直被降维打击了。因为1-n本来就是顺序排列,然后遇到si=0的时候,只需要和后面颠倒一下,就可以满足不是全排列了,然后si=1的时候,又是全排序。
#include <algorithm>
#include <iostream>
#include <bits/stdc++.h>
#include <vector>
using namespace std;


int main() {
    int n;cin>>n;
    string s;cin>>s;
    if(s[n-1]=='0'){
        cout<<-1<<endl;
        return 0;
    }
    vector<int>p(n);
     for(int i=0;i<n;i++){
        p[i]=i+1;
     }
    for(int i=0;i<n;i++){
        if(s[i]=='0')swap(p[i],p[i+1]);
        cout<<p[i]<<" ";
    }
    
    
   
}

发表于 2025-12-18 22:23:42 回复(0)
import sys

n=int(input())
s=list(map(int,input()))
if s[-1]==0:
    print("-1")
    sys.exit()
num_list=[i for i in range(1,n+1)]
output_list=[0 for i in range(1,n+1)]
count=0
for idx,flag in enumerate(s):
    if flag==1 and idx==0:
        output_list[0]=1
    elif idx>=1 and flag==1 and s[idx-1]==1:
        output_list[idx]=idx+1
    elif flag==0:
        count+=1
    elif flag==1 and count>0:
        output_list[idx-count:idx]=[i for i in range(idx+1,idx-count,-1)]
        count=0
print(' '.join(map(str,output_list[:n])))

发表于 2025-12-16 20:47:17 回复(0)
import sys

# 可以先构造一个元素为 1 到 n 的数组 nums
# 然后遍历 s 的每一位字符
# 如果 s[i] = 1, nums[i] 就保持不变;如果 s[i] = 0, 就交换 nums[i] 和 num[i+1]
# 最后一个数字 nums[end] 无法再往后找数字交换了,所以 s[end] 必须 = 1

# 上面的方法空间复杂度是 O(n), 去掉 nums 数组,空间复杂度就是 O(1) 了

n = int(input())
s = input().strip()

if s[-1] == '0':
    print(-1)
    sys.exit()

prev = 0
for i in range(n):
    current = i + 1
    if s[i] == '1':
        if prev == 0:
            # 如果前面没有数字被换到这里,就输出当前的数字
            print(current, end=' ') 
        else:
            # 如果前面的数字被换到这里了,输出前面的数字
            print(prev, end=' ')
            prev = 0
    else:
        # 遇到 0 了, 先把后面的数字输出
        print(current + 1, end=' ')
        if prev == 0:
            # 把当前数字存起来,后面再输出
            prev = i + 1

发表于 2025-12-04 21:21:09 回复(0)
#include <cstddef>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    string s;
    cin>>n>>s;
    if(n>100000){cout<<"-1";return 0;}
    vector<int> v,v1;
    if(s[n-1]=='0'){cout<<"-1";return 0;}//末尾必为1
    else{
        int pos1=0;
        while(s.find('1')!=string::npos){
        int pos=s.find('1')+1;//新1的位置
        v.push_back(pos+pos1);//将1的位置存入v
        s.erase(0,pos);
        pos1+=pos;
        }
        int y=0;
        for(int i:v){
            for(int j=i;j>y;j--){
                v1.push_back(j);
            }
            y=i;
        }
        if(s.size()){
            for(int i=n;i>y;i--){
                v1.push_back(i);
            }
        }
        for(int i:v1){
            cout<<i<<" ";
        }
        
    }
}
// 64 位输出请用 printf("%lld")

发表于 2025-11-19 15:53:03 回复(1)
C++首发题解:
题意理解:所谓s[i]=1,是指前i位由1到 i 构成且不重复,i从1开始。比如s[2]=1,则前2位必然由1-2构成且数字不重复。显然,s[2]=0则表示前2位必然不满足1-2构成,数字不重复。数字不重复其实不用管,因为只要破坏前 i 位由1到 i 构成这个条件,也能满足题意,比如s=001,则3 2 1满足前1位不是由1到1构成,前2位不是由1到2构成,前3位由1-3构成且不重复,即3的排列。所以只需在p中填充1-n的数字,但是排列顺序不同。
解法:首先不难想到一个共识,就是p(n)中的数字都是1-n,填充数字的时候,取的数不能重复。然后这题其实是要从后往前遍历,填充数字。为什么不是从前往后呢?因为从前往后很难符合题目,比如正向贪心法:遇到0则填充最大值破坏序列,不让前n位由1-n构成,比如不让前2位包含1 2,而是3 2,然后遇到1填充最小值。验证一下:001->3 2 1,看似合理,但如果是011呢?结果就是3 1 2,前2位不是1 2或2 1!显然,这种方***把最大值前置!所以要从后往前遍历,进行一个逆向分段构造。
核心原则
每个 '1' 在位置 i 要求:
前 i+1 个元素 = {1, 2, ..., i+1} 的一个排列。
因此,任何出现在位置 ≤ i 的元素都必须 ≤ i+1。
所以,'0' 位置不能随意填大数(如 n),而只能填 不超过下一个 '1' 所在前缀上限 的数。
构造策略
从右往左扫描,每当遇到 '1',就将其与左侧连续的 '0' 合并为一个“责任段”。将当前能填充的最大值放在段首(破坏 '0' 前缀的排列性),其余段内数字递减填充即可(升序填充也行,答案不唯一)。也就是说,这个策略是让最大值不总是提前,而是在规定的小区间内提前!注意这里的段内数字是当前最大值到当前最大值 - 段长+1,比如段长4,当前最大值5,则段内数字必须是2到5,且段首必须是5。
例:01011,首先检测到1这段,填充5。然后检测到01这段,填充4 3,又检测到01这段,填充2 1,总序列是2 1 4 3 5,满足前1位不是1,前2位有1和2,前3位不是由1-3构成,前4位有1-4,前5位有1-5。

AC代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
    string s;
    int n;
    cin >> n >> s;
    vector<int>p(n);
    if (s.back() == '0')cout << -1;
    else {
        int N = n;
        for (int i = n - 1; i >= 0; i--) {
            if (s[i] == '1') {
                int j = i - 1;
                while (j >= 0 && s[j] == '0') j--;
                for (int k = j + 1; k <= i; k++)p[k] = N--;
            }
        }
        for (int i = 0; i < n; i++) {
            if (i) cout << ' ';
            cout << p[i];
        }
    }
}


发表于 2025-11-09 21:40:42 回复(0)
卧槽,自己想的算法,没看评论区,居然一次性通过所有用例,我运气真好
总体思路:先把数组 p按递增序列初始化,然后对比字符串s,遇到s[i]=1,则p[i]的值保持不变。遇到s[i]=0,则找下一个s[b]=1的位置的p[b]和当前p[i]交换数值,如果找不到s[b]=1的位置等于1,则表示无解。
#include <stdio.h>
#include <stdlib.h>
//让我判断是不是匹配还好说,让我构造??
//只能找规律,再想五分钟想不出来就老实看答案。
//好像找到规律了,遇到1则填对应的数字即可,遇到0则和下一个是1的位置交换数字即可,交换完之后就跳过下一个1的位置,不过这种只适合有解的情况啊。如果后面找不到有1的情况,则就当无解把
int main() {
    int n;
    
    scanf("%d",&n);

    char *string=malloc(sizeof(char)*(n+1));
    scanf("%s",string);

    //去掉字符串的0位置,然后末尾的'\0'也不要了,这样结果才能一一对应
    for(int i=n;i>0;i--)
    {
        string[i]=string[i-1];
    }

    int *result=malloc(sizeof(int)*(n+1));
    for(int i=0;i<=n;i++) //初始结果数组为递增数组,但是后面元素下标为0的数字不用
    {
        result[i]=i;
    }

    //然后和字符串一一对应的了,找能交换的位置了
    for (int i=1; i<=n; ) {
        if(string[i]=='1')  //遇到1则结果数组保持原样
        {
            i++;
        }else if(string[i]=='0')         //遇到0则找下一个为1的位置交换
        {
            int a=i;//记录当前位置
            while(string[i]=='0')  //跳过所有0的位置
            {
                i++;
                if (i>n) {  //如果找完后续所有位置都没有1的位置,则无解
                    printf("-1");
                    return 0;
                }
            }
            //来到了string[i]=='1'的位置,和a的职位交换
            int temp=result[a];
            result[a]=result[i];
            result[i]=temp;    //交换
            i++; //移动到下一个位置继续探索
        }
    }

    //输出result数组的所有结果
    for(int i=1; i<=n; i++)
    {
        printf("%d ",result[i]);
    }
    
    return 0;
}


发表于 2025-10-18 15:14:14 回复(0)
n = int(input())
s = input()
ls = [i for i in range(1,n+1)]
i = 0
flag = True
if s[-1] == '0':
    flag  = False
while i<n and flag:
    if s[i] == '0':
        nex = s.find('1',i)
        if nex==None:
            flag = False
            break
        tmp = ls[i]
        ls[i] = ls[nex]
        ls[nex] = tmp
        i = nex
        continue
    i += 1

if flag:
    for x in ls:
        print(x,end=' ')
else:
    print(-1)

发表于 2025-10-10 12:01:03 回复(0)
import java.util.*;

//找到1就倒叙添加到list
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        in.nextLine();
        String s = in.nextLine();
        int len = s.length();
        ArrayList<Integer> res = new ArrayList<>();
        for(int i = 0; i < len; i++){
            if(s.charAt(i) == '0')
                continue;
            int temp = res.size();
            for(int j = i + 1; j > temp; j--){
                res.add(j);
            }
        }
        if(n != res.size())
            System.out.println("-1");
        else{
            for(int i = 0; i < n; i++){
                if(i == n - 1)
                    System.out.println(res.get(i));
                else
                    System.out.print(res.get(i) + " ");
            }
        }
    }
}
发表于 2025-09-10 19:01:04 回复(0)
using System;
using System.Collections.Generic;
using System.Linq;
public class Program {
    public static void Main() {
        var n = int.Parse(Console.ReadLine ());
        var strList = Console.ReadLine ().Select(x => int.Parse(x.ToString())).ToList();
        var numberList = Enumerable.Range(1, n).ToList();
        if (strList.Last() == 0) {
            Console.WriteLine(-1);
            return;
        }
        for (int i = 0; i < strList.Count - 1; i++) {
            if (strList[i] == 0) { // 如果=0,则和数字的后面一位交换位置
                int temp = numberList[i];
                numberList[i] = numberList[i + 1];
                numberList[i + 1] = temp;
            }
        }
        Console.WriteLine(string.Join(" ", numberList));
    }
}

发表于 2025-08-14 13:23:19 回复(0)
控制台传过来的字符串为str,①无结果:当str的结尾为0时,说明不可能有满足题意的字符顺序,直接输出-1。
②有结果:遇到1时再填充字符,两层for循环,外层right从前到后寻找字符“1”,
内层j从上一个字符“1”后开始遍历到外层找到的1,填充为j + 2(下标比当前位置靠后。比如第二个位置,我们输入3),
遍历到达“1”(right)时,输出left + 1的值,再把left赋值为right + 1。
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) {
            int lens = in.nextInt();
            in.nextLine();
            String str = in.nextLine();
            char[] chars = str.toCharArray();

            if (chars[chars.length - 1] == '0'){
                System.out.println(-1);
            }else{
                int impossible = 2;
                int possible = 1;
                int left = 0;
                for (int right = 0; right < chars.length; right++){
                    if (chars[right] == '1'){
                        for (int j = left; j < right; j++){
                            System.out.print(j + 2 + " ");
                        }
                        System.out.print(left + 1 + " ");
                        left = right + 1;
                    }
                }
            }
        }
    }
}

发表于 2025-07-21 01:42:30 回复(0)

题目含义:
(1)若 ,则数列 {,..., } 必须由数字 1 ~ {i+1} 组成,且每个数字只出现一次,其中 i 从1开始;
(2)若,则表示数列 {,..., } 至少有一个元素大于数字 i。

'''
n = int(input())
s = input()

if s[-1] == '0':
print(-1)
else:
res = [i for i in range(1, n+1)]
for i in range(n):
if s[i] == '0':

s 中第i个元素为'0',则排列中第i个元素的值必须大于i

res[i], res[i+1] = res[i+1], res[i]
print(' '.join(map(str, res)))
'''

发表于 2025-06-23 22:16:37 回复(0)