C - TT 的神秘任务 - X
TT 的神秘任务系列。
这一次,TT 得到了一个长度为 N 的字符串,任务要求在原字符串中至多删去一个字符,使得字符串的字典序尽可能小。
字符串字典序的比较优先级如下:
从左往右第一个不同字符的 ASCII 值的大小关系
字符串长度
Input第一行给出 N(2 ≤ N ≤ 2e5)。
第二行给出一个长度为 N,且仅包含小写字母的字符串。Output输出字典序最小的字符串。
Examples
Input
3
aaa
Output
aa
Input
5
abcda
Output
abca
解题思路:
这是一道思维上比较单一的题目,但是自己没能够在短时间内想出正确的逻辑,相反,自己最初做的时候采取了完全暴力的解决方案,其实感觉当时做题时有些过于莽撞,一种试错的心态在写程序时是完全不可取的,其既影响正确方向上的思考,也影响心情。发现自己在做程序时还存在的一个问题便是过于依靠大脑去思考,其实有些题目用笔写一下是更有效的,这道题目自己前前后后花费45分钟,确实暴漏了自己很多缺点。
讲一下这个题目,题目总体来讲不是很难,但需要一种反射式的思维,这与平常的见多识广或是凭空多思考一些问题有关。对于删除其中的某一个字符,我们可以理解成字符后面的所有字符整体向前移一位,这个问题我们可以简单的将其抽象为一个连续的函数图像的平移问题,我们的最终追求是选择某一点之后的图像进行左移,使得原图像最先能够高于平移后的函数图像,很显然我们我在下降区间中去找,而且是第一个下降区间的第一个元素。而这时,脱离图像,我们会发现这道题目的本质好像是在维护一个单调非递减的序列。自己在这个题目上做的不够好,感觉还是对于序列单调性的思维深度不够,有待加强。
#include<iostream>
#include<string>
using namespace std;
int N;
string s;
int label=0;
int main()
{
cin>>N;
cin>>s;
for(int i=1;i<N;i++)
{
if(s[i]>=s[i-1])
label=i;
else
break;
}
string fun=s.substr(0,label)+s.substr(label+1,N-label-1);
cout<<fun<<endl;
}在这里插入代码片
D - 瑞瑞爱上字符串
瑞瑞最近迷上了字符串,因此决定出一个字符串的题。
给定两个正整数 N、K,考虑所有由 N - 2 个 a 和 2 个 b 组成的字符串,要求输出其中字典序第 K 小的。
例如当 N = 5 时,共有如下 10 种组成方式:
aaabb
aabab
aabba
abaab
ababa
abbaa
baaab
baaba
babaa
bbaaa
Input
多组数据,第一行给定 T,表示数据组数。(1 ≤ T ≤ 1e4)
对于每组数据,给出两个正整数 N、K。(3 ≤ N ≤ 1e5, 1 ≤ K ≤ min(2e9, N * (N-1) / 2 ))
N 的总和不会超过 1e5。
Output
对于每组数据,输出长度为 N 的字典序第 K 小的字符串。
Example
Input
7
5 1
5 2
5 8
5 10
3 1
3 2
20 100
Output
aaabb
aabab
baaba
bbaaa
abb
bab
aaaaabaaaaabaaaaaaaa
解题思路:
对于本道题目而言,感觉这更像是一道数学题,思路很简单,但就是没做出来。。这个题目的要求不是很高,题目中明确强调N的总和不会超过1e5,但自己做题的时候就是没看见。。1e5的限制下足以满足暴力求解的要求,但不过,我们还是最好在此基础上温习以下二分做法,模拟期间,自己的思路很明确,但是二分的接口总是处理不好,通过这道题目,我们再次了解一下二分。二分的写法基本上是固定的,一般严谨的写法会保留4个变量,l,r,mid,ans.二分的处理可以求解四种情况,1.大于等于的最小值。2.大于的最小值。3,小于等于的最大值。4,小于的最大值。在这里,是按自己的预想思路进行选择的。希望通过这次我们能够记住二分的标准写法,不要再出现懂思想但写不出来的情况。(因为那样真的很影响心情),另外注意一下,二分通常要使用long long数据类型,脑海中要时刻注意。
#include<iostream>
#include<string>
using namespace std;
long long T,N,K;
long long a,b;
long long erfen(long long K)
{
long long l=1;
long long r=N;
long long mid=(r+l)/2;
long long ans=0;
while(l<=r)
{
if(mid*(mid-1)/2<K)
l=mid+1;
else
{
ans=mid;
r=mid-1;
}
mid=(r+l)/2;
}
return ans;
}
int main()
{
cin>>T;
while(T--)
{
cin>>N>>K;
long long a=erfen(K);
long long b=K-(a-1)*(a-2)/2;
for(int i=1;i<=N;i++)
{
if((i!=N-a+1)&&(i!=(N-b+1)))
cout<<'a';
else
cout<<'b';
}
cout<<endl;
}
}在这里插入代码片