[NOIp1998 T2] 拼数(字符串,排序)

该博客介绍了如何解决NOIP1998年的T2问题,即如何通过排序正整数形成一个最大的多位整数。博主提出将数字视为字符串,并以特定方式排序,即如果字符串a+b小于b+a,则b应该在a之前,以此作为排序依据,最终实现高效求解最大整数的方法。

题目

描述

设有n个正整数(n≤20),将它们联接成一排,组成一个最大的多位整数。
例如:n=3时,3个整数13,312,343联接成的最大整数为:34331213
又如:n=4时,4个整数7,13,4,246联接成的最大整数为:7424613

输入

第一行,一个正整数n。
第二行,n个正整数。

输出

一个正整数,表示最大的整数

输入样例

3
13 312 343

输出样例

34331213

解题思路

(注:以下“a+b”形式表示a字符串后接上b字符串所得字符串)

如果直接暴搜,复杂度高达O(n!)O(n!),即使加了剪枝也无济于事。
那么这道题多半是以一种特定的方式排序后输出。
怎么排序呢?
我们把数字看成字符串,考虑构成一个字符串中的任意两个子字符串a和b,若a+b < b+a,那么显然我们把b放在a的前面更优。举个例子,100+10 < 10+100,所以10100比10010更优(这个例子也可以排除直接比较a和b的大小的做法)。因此,我们就以此为排序依据,排序后一次输出即可。


Code

用C++的string是真的方便!

#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>

using namespace std;

int n;
string s[25];
bool cmp(string a, string b){
    return a + b > b + a;
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) cin >> s[i];
    sort(s+1, s+n+1, cmp);
    for(int i = 1; i <= n; i++) cout << s[i];
    return 0;
}
P11361 [NOIP2024] 编辑字符串 提交答案加入题单复制题目 提交 14.73k 通过 5.00k 时间限制 1.00s 内存限制 512.00MB 复制 Markdown 中文 折叠 进入 IDE 模式 题目描述 小 M 有两个长度为 n 且字符集为 {0,1} 的字符串 s 1 ​ ,s 2 ​ 。 小 M 希望两个字符串中对应位置字符相同的出现次尽可能多,即满足 s 1,i ​ =s 2,i ​ 的 i(1≤i≤n) 尽可能多。为此小 M 有一个字符串编辑工具,这个工具提供的基本操作是在一个字符串中交换两个相邻的字符。为了保持字符串的可辨识性,规定两个字符串中的部分字符不能参与交换。小 M 可以用工具对 s 1 ​ 或 s 2 ​ 进行多次字符交换,其中可以参与交换的字符能够交换任意多次。 现在小 M 想知道,在使用编辑工具后,两个字符串中对应位置字符相同的出现次最多能有多少。 输入格式 本题包含多组测试据。 输入的第一行包含一个整 T,表示测试据的组。 接下来包含 T 组据,每组据的格式如下: 第一行包含一个整 n,表示字符串长度。 第二行包含一个长度为 n 且字符集为 {0,1} 的字符串 s 1 ​ 。 第三行包含一个长度为 n 且字符集为 {0,1} 的字符串 s 2 ​ 。 第四行包含一个长度为 n 且字符集为 {0,1} 的字符串 t 1 ​ ,其中 t 1,i ​ 为 1 表示 s 1,i ​ 可以参与交换,t 1,i ​ 为 0 表示 s 1,i ​ 不可以参与交换。 第五行包含一个长度为 n 且字符集为 {0,1} 的字符串 t 2 ​ ,其中 t 2,i ​ 为 1 表示 s 2,i ​ 可以参与交换,t 2,i ​ 为 0 表示 s 2,i ​ 不可以参与交换。 输出格式 对于每组测试据输出一行,包含一个整,表示对应的答案。 输入输出样例 输入 #1复制 1 6 011101 111010 111010 101101 输出 #1复制 4 说明/提示 【样例 1 解释】 最开始时,s 1 ​ =011101,第 4 和第 6 个字符不能参与交换;s 2 ​ =111010,第 2 和第 5 个字符不能参与交换。 考虑如下操作:先交换 s 1,1 ​ 与 s 1,2 ​ 得到 s 1 ​ =101101,再交换 s 1,2 ​ 与 s 1,3 ​ 得到 s 1 ​ =110101,最后交换 s 2,3 ​ 与 s 2,4 ​ 得到 s 2 ​ =110110。此时 s 1 ​ 与 s 2 ​ 的前 4 个位置上的字符都是相同的。可以证明不存在更好的方案,故输出 4。 【样例 2 解释】 见附件的 edit/edit2.in 与 edit/edit2.ans。 该样例共有 10 组测试据,其中第 i(1≤i≤10) 组测试据满足据范围中描述的测试点 2i−1 的限制。 【据范围】 对于所有的测试据,保证:1≤T≤10,1≤n≤10 5 。 测试点编号 n≤ 特殊性质 1∼4 10 无 5,6 10 3 A 7,8 10 5 A 9,10 10 3 B 11,12 10 5 B 13,14 10 3 C 15,16 10 5 C 17,18 10 3 无 19,20 10 5 无 特殊性质 A:保证 s 1 ​ 的所有字符相同。 特殊性质 B:保证 t 1 ​ =t 2 ​ 。 特殊性质 C:保证 t 1 ​ 和 t 2 ​ 中各自恰有一个字符 0。 附件下载 edit.zip 112.79KB 我的代码如下,请写出B,C两性质,我只想得部分分 #include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(0); int T; cin >> T; while (T --) { int n, cnt = 0; cin >> n; string s1, s2; string t1, t2; cin >> s1 >> s2; s1 = '#' + s1, s2 = '#' + s2; cin >> t1 >> t2; t1 = '#' + t1, t2 = '#' + t2; bool A = true; for (int i = 1; i < n; i ++) { if (s1[i] != s1[i + 1]) { A = false; break; } } bool B = true; for (int i = 1; i < n; i ++) { if (t1[i] != t1[i + 1]) { B = false; break; } } bool C = true; int cnt1 = 0, cnt2 = 0; for (int i = 1; i < n; i ++) { if (cnt1 >= 2 || cnt2 >= 2) break; if (t1[i] == 0) cnt1 ++; if (t2[i] == 0) cnt2 ++; } if (cnt1 == cnt2 == 1) C = true; else C = false; //pre_work for (int i = 2; i < n; i ++) { if (t1[i] == 1 && t1[i - 1] == 0 && t1[i + 1] == 0) t1[i] = 0; if (t2[i] == 1 && t2[i - 1] == 0 && t2[i + 1] == 0) t2[i] = 0; } // 特殊性质 A:保证 s1 的所有字符相同 if (A == true) { for (int i = 1; i <= n; i ++) { if (s1[i] == s2[i]) cnt ++; } cout << cnt << '\n'; } else { } } return 0; }
最新发布
08-07
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值