牛客网小白月赛34题解
Posted 风去幽墨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客网小白月赛34题解相关的知识,希望对你有一定的参考价值。
A dd爱科学1.0
题意:
给出一个字符串,问最少修改多少个字母使得该字符串为非递减字符串?
题解:
动态规划。
原问题的子问题:
最少修改多少个字母使得前i个字符形成的字符串为非递减序列,且保证最后一个字符为j。
定义:
dp[i][j] 保证前i个字符串为非递减且最后一个字符为j的最少修改次数
转移方程:
- 当s[i] != j时即第i个字符不是j时,需要将s[i]个改成字符j再加上min(dp[i-1][k])。min(dp[i-1][k])表示前i-1个字符形成非递减且最大字符小于等于j的最少修改次数。
dp[i][j] = min(dp[i-1][k]) +1 其中k<=j (保证非递减) - 当s[i] == j时即第i个字符恰好是j时。不需要修改s[i],min(dp[i-1][k])解释同上。
dp[i][j] = min(dp[i-1][k]) 其中k<=j (保证非递减)
最终答案为min(dp[n-1][k]) (0<=k<=25)
维护:
min(dp[i-1][k]) ,可以用二维数组mi[i-1][x]维护,mi[i-1][x]表示,前i-1个字符中最大字符为k的最小修改次数。由于每次使用min(dp[i-1][k])时都是i与i-1的关系,所以可以省略掉i-1这一维度,即可以使用一维数组mi[x]进行维护。
mi[x] = min(mi[x-1],dp[i-1][x]) (0<=x<=25,大写字母的范围)很简单的维护思路。可以类比为:给出一个数组,求出前x个元素中的最小值。
代码:
#include <bits/stdc++.h>
using namespace std;
int n;
const int maxn = 1e6+5;
int dp[maxn][27],mi[27];
int main()
{
cin>>n;
string s;
cin>>s;
memset(dp,0x3f,sizeof(dp));//初始化为0x3f3f3f3f 1e9左右
//初始化dp[i][j]
for(int j=0;j<26;++j)
dp[0][j]=1;
dp[0][int(s[0]-'A')]=0;
//初始化mi[x]
mi[0]=dp[0][0];
for(int i=1;i<26;++i)
{
mi[i]=min(mi[i-1],dp[0][i]);
}
for(int i=1;i<n;++i)
{
int x =int(s[i]-'A');
//状态转移
dp[i][x]=min(dp[i][x],mi[x]);
for(int j=0;j<26;++j)
{
if(j==x)continue;
dp[i][j]=min(dp[i][j],mi[j]+1);
}
//维护mi[x]
mi[0]=dp[i][0];
for(int j=1;j<26;++j)
{
mi[j]=min(mi[j-1],dp[i][j]);
}
}
int ans = (1<<30);
//取最小值
for(int i=0;i<26;++i)
{
ans = min(ans,dp[n-1][i]);
}
cout<<ans;
return 0;
}
E dd爱旋转
题意:
给出一个n*n二维矩阵,有两种操作:
- 顺时针旋转180度
- 水平镜像,以中间行为轴水平镜像
给出q个操作,问所有操作完成后,二维矩阵转换成什么了?
题解:
手动模拟一下。
操作1:相当于是a[i][j] = a[n-i+1][n-j+1]
操作2:相当于是a[i][j] = a[n-i+1][j]
再模拟一下,发现结果与操作顺序无关,且操作1与操作2,再进行偶数次时与原矩阵相比不会产生变化。
所以结果就是看操作1与操作2是否执行了奇数次。然后模拟即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,q;
int a[1005][1005];
int main()
{
cin>>n;
for(int i=0;i<n;++i)
{
for(int j=0;j<n;++j)
{
cin>>a[i][j];
}
}
cin>>q;
int dj = 0,px = 0;
while(q--)
{
int op ;
cin>>op;
if(op==1)
dj++;
else
px++;
}
dj%=2;
px%=2;
if(dj==1&&px==1)
{
for(int i=0;i<n;++i)
{
for(int j=n-1;j>=0;--j)
{
cout<<a[i][j]<<" ";
}
cout<<"\\n";
}
}
else if(dj==1)
{
for(int i=0;i<n;++i)
{
for(int j=0;j<n;++j)
{
cout<<a[n-1-i][n-1-j]<<" ";
}
cout<<"\\n";
}
}
else if(px==1)
{
for(int i=n-1;i>=0;--i)
{
for(int j=0;j<n;++j)
{
cout<<a[i][j]<<" ";
}
cout<<"\\n";
}
}
else
{
for(int i=0;i<n;++i)
{
for(int j=0;j<n;++j)
{
cout<<a[i][j]<<" ";
}
cout<<"\\n";
}
}
return 0;
}
F dd爱框框
题意:
给出一个长度为n的数组,和目标x。
问子区间[l,r]的元素和大于等于x的最小子区间是多少?
最小子区间的定义:区间长度最小,区间长度相同时,左边界最小。
题解:
滑动窗口。
定义 l ,r,sum,分别为区间左右编辑,以及区间和。
r不断地向右移动,过程中维护sum。
过程中若是sum-a[l]>=x的话,证明在满足题意得情况下,区间可以更小,则不断增大左边界l,直至sum-a[l]<x。
当sum>=x时,注意维护最小区间。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,x;
int a[10000005];
int main()
{
cin>>n>>x;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int anslen=x,ansl=1;
int l=1,r=1,sum=0;
while(r<n)
{
sum+=a[r++];
while(sum-a[l]>=x)
{
sum-=a[l++];
}
if(sum>=x&&r-l<anslen)
{
anslen=r-l;
ansl=l;
}
}
cout<<ansl<<" "<<ansl+anslen-1;
return 0;
}
以上是关于牛客网小白月赛34题解的主要内容,如果未能解决你的问题,请参考以下文章