连续上分咯
1861A - Prime Deletion
题意:给定一个字符串,包含了1~9数字各一个,你可以删除最多7个数字,要求删完以后的字符串组成的数字为素数。
思路:13与31都是素数,因此只需要看1在3的前面还是后面再决定输出13还是31即可。
void solve()
{
string s;
cin>>s;
map<int,int>mp;
for(int i = 0 ; i <= 8 ; i ++){
int x = s[i] - '0';
mp[x] = i;
}
if(mp[3] < mp[1]){
cout<<31<<endl;
}
else{
cout<<13<<endl;
}
}
1861B - Two Binary Strings
题意:给定两个01串,其中第一个字符是0,最后一个字符是1。你可以对字符串进行如下操作:选定两个相同的字符,将字符串中这两个字符中间的字符变成选中的字符。求最终两个字符串能否相同。
思路:因为头是0,尾是1。所以只需要在字符串中选择一段连续的01,然后0左边全部变为0,1右边全部变为1即可。若两个字符串中有相同位置的01,那么他们最终就能相同。
void solve()
{
string s1 , s2;
cin>>s1>>s2;
int len = s1.size();
for(int i = 1 ; i < len ; i ++){
if(s1[i - 1] == '0' && s2[i - 1] == '0' && s1[i] =='1' && s2[i] =='1'){
cout<<"YES\n";
return;
}
}
cout<<"NO\n";
}
1861C - Queries for the Array
题意:起初有一个空的栈,接下来给出一段字符串,其中按顺序‘+’代表了一个数入栈,‘-’代表了一个数出栈,‘0’代表了栈是非递增的,‘1’代表了栈是递增的。令栈中元素数量少于2的情况默认为递增。求给出的字符串能否满足条件。
解释:例如字符串“+ + 0 - 1”,代表了先两个数入栈,然后整个栈非递增,然后再出栈一个数,最后栈是递增的。先入 1 ,再入0,此时栈是非递增的。然后0出栈,栈中只剩下1个元素,为递增。所以该字符串能够满足条件。
思路:这是一道反悔贪心的题目,我们将相邻两个数字之间的操作看成一个过程,总共有4种可能:1、 1xxx1的情况,此时无论中间是怎么样的,都一定能够满足递增条件。2、1xxx0的情况,此时我们必须要保证栈上能够新增至少一个数,才能保证变为非递增的。3、0xxx1的情况,此时我们必须要满足在整个过程当中,将前面的非递增的数减去才能满足条件。4、0xxx0的情况,这种情况最为复杂:若是0 - - - 0,那么必须要保证栈中倒数第四个数是非递增的。而这里便是需要我们反悔的地方了。
怎么贪心?假设 x 为我们需要将末尾第x个数删掉之后才能变得递增。我们在0xxx0 与 1xxx0的情况之下,都尽可能的满足 x = 1 , 特殊情况: 0+++0 的情况,那么 x = x + 3了。而处理0 - - - 0的情况,我们还需要将 x 增大。因此我们还需要假设 y 为 x 的最大取值。在 1 xxx 0 的情况之下,y的值为最终整个过程中加了几个数上去。在0 xxx 0 的情况之下,y 先需要减去整个过程当中删了前面多少个数,然后再加上整个过程当中加了几个数。处理0 - - - 0 时,若y < 3 则代表删了3个数以后必然是递增的,那么便无法满足了。
void solve()
{
string s;
cin>>s;
int jinjian = 0 , jinjia = 0 , jian = 0 , jia = 0 ;
int t_max = 0;//最多有连续多少个数是递减的
int t_min = 1;
int cnt = 0;
int len = s.size();
int flag = 1;
for(int i = 0 ; i < len ; i ++){
if(s[i] == '+'){
jia++;
jinjia = max(0 , jinjia + 1);
jinjian = max(jinjian , jian - jia);
cnt++;
}
if(s[i] == '-'){
jian++;
jinjia = max(0 , jinjia - 1);
jinjian = max(jinjian , jian - jia);
cnt--;
}
if(s[i] == '1'){
if(flag == 0){
if(jinjian < t_min){
cout<<"NO\n";
return;
}
}
t_max = 0;
t_min = 0;
jia = 0;
jian = 0;
jinjia = 0;
jinjian = 0;
flag = 1;
}
if(s[i] == '0'){
if(cnt == 0 || cnt == 1){
cout<<"NO\n";
return;
}
if(flag == 1){
if(jinjia == 0){
cout<<"NO\n";
return;
}
else{
t_max = jinjia;//加的几个数全是递减
t_min = 1;
}
}
else{
if(jinjia == 0){
if(t_max <= jinjian){
cout<<"NO\n";
return;
}
}
else{
t_max = max(0 , t_max - jinjian);
t_max += jinjia;
if(jinjian == 0){
t_min += (jia - jian);
}
else{
t_min = 1;
}
}
}
jian = 0;
jia = 0;
jinjia = 0;
jinjian = 0;
flag = 0;
}
}
cout<<"YES\n";
}
1861D - Sorting By Multiplication
题意:给定一个数组,每次操作可以选择 l ,r , x 。令。求让整个数组严格递增的最小操作数。
思路:一道最小操作数的dp题,因为x可以任选,因此 可以分为三种情况:1、负无穷。2、原数。3、正无穷。因此假设dp[i][0]代表了前i个数,且
为负无穷情况下,整个数组严格递增的最小操作数。dp[i][1]代表了前i个数,且
不变情况下,整个数组严格递增的最小操作数。dp[i][2]代表了前i个数,且
为正无穷下,整个数组严格递增的最小操作数。于是有状态转移方程:
假设a[i] > a[i - 1]:
此时如果要将 变为负无穷且大于
,不能和
乘同一个系数,因此需要操作数 + 1。
如果要将 不变,那么直接从
转移过来即可。
如果要将 变成正无穷,那么和
乘同一个系数即可。或者自己再单独乘一个系数(操作数 + 1)
反之a[i] < a[i - 1] :
此时如果要将 变为负无穷且大于
,和
乘同一个系数即可。
如果要将 不变,那么直接从
转移过来即可。
如果要将 变成正无穷,需要自己单独乘一个系数,操作数+1。
最后输出第n位,为负无穷,原数,正无穷的最小操作数。
void solve()
{
int n;
cin>>n;
int dp[n + 5][3];//-无穷,不变,正无穷
memset(dp , 0x3f , sizeof dp);
int a[n];
dp[0][0] = 1;
dp[0][1] = 0;
dp[0][2] = 1;
for(int i = 0 ; i < n ; i ++){
cin>>a[i];
}
for(int i = 1 ;i < n ; i ++){
if(a[i] < a[i - 1]){
dp[i][0] = dp[i - 1][0];
}
else{
dp[i][0] = dp[i - 1][0] + 1;
}
if(a[i] > a[i - 1]){
dp[i][1] = min(dp[i - 1][1] , dp[i - 1][0]);
}
else{
dp[i][1] = dp[i - 1][0];
}
if(a[i] > a[i - 1]){
dp[i][2] = min(dp[i - 1][1] + 1 , min(dp[i - 1][2] , dp[i - 1][0] + 1));
}
else{
dp[i][2] = min(dp[i - 1][1] + 1 , min(dp[i - 1][2] + 1 , dp[i - 1][0] + 1));
}
}
int ans = 1e7;
for(int i = 0 ; i < 3; i ++){
ans = min(ans , dp[n - 1][i]);
}
cout<<ans<<endl;
}