笔试强训:Week-3 - 详解
目录
一、牛牛冲钻五(模拟)


#include
using namespace std;
int main() {
int T;cin>>T;
while(T--)
{
int n,k;
cin>>n>>k;
string str;
cin>>str;
int sum=0;
for(int i=0;i=2&&str[i-1]=='W'&&str[i-2]=='W')sum+=k;
else sum+=1;
}
else sum-=1;
}
cout<
二、最长无重复子数组(滑动窗口)

注意hash的key值是in和out,老是写成left和right
class Solution {
public:
int maxLength(vector& arr) {
unordered_map hash;
int ret=1,left=0,right=0,n=arr.size();
if(n==0||n==1)return n;
while(right1)
{
int out=arr[left++];
--hash[out];
}
ret=max(ret,right-left+1);
++right;
}
return ret;
}
};
三*、重排字符串(贪心)


优先处理出现次数最多的那个,每隔一个位置放一个,x<=(n+1)/2才可以排,否则直接cout<<"no"

#include
#include
using namespace std;
int main()
{
int n;
string s;
cin>>n>>s;
int MaxCount=0,hash[26]={0};
char MaxChar;
for(auto&ch:s)
{
if(++hash[ch-'a']>MaxCount)
{
MaxCount=hash[ch-'a'];
MaxChar=ch;
}
}
if(MaxCount>(n+1)/2)cout<<"no";
else
{
cout<<"yes"<=n)index=1;
s[index]=chr;
index+=2;
}
}
}
cout<
四、乒乓球筐(哈希)


先遍历s2,存进,然后遍历s1,最后再遍历26个字母,如果有剩下的就cout<<"No";
#include
using namespace std;
int main() {
string s1,s2;
cin>>s1>>s2;
int hash[26]={0};
int n=s1.size(),m=s2.size();
for(int i=0;i
或者先遍历s1,然后遍历s2,如果hash[]<0说明s1包不住s2,cout<<"No",此外,对于这种二元判断的,我们可以添加一个bool变量来实现cout哪个,这样就不用写两个return了
#include
#include
using namespace std;
int main() {
string a,b;
cin>>a>>b;
int hash[26]={0};
for(auto&ch:a) ++hash[ch-'A'];
bool ret=true;
for(auto&ch:b)
{
if(--hash[ch-'A']<0)
{
ret=false;
break;
}
}
cout<<(ret?"Yes":"No");
return 0;
}
五?、组队竞赛(排序+贪心)


做错了,错误的以为是排序后从下标1开始+=3加到sum。
贪心的想,应该是排序后,因为我们得是第2大的,那么我们取数就得保证还有一个数比我大,那么我们从倒数第二的开始往前选,index-=2,找到n个,就是最大的。
#include
#include
using namespace std;
const int N=1e5+5;
int n;
long long a[N*3];
int main() {
cin>>n;
for(int i=0;i>a[i];
sort(a,a+3*n);
//从倒数第二个开始
int pos=3*n-2;
long long ret=0;
//取n个
while(n--){
ret+=a[pos];
pos-=2;
}
cout<
六、删除相邻数字的最大分数(多状态dp)


没想到自己能想到这么做。
无非就是不能接着选的问题,遍历到i的时候无非就是i选和不选的问题,然后在dp[i-1]和dp[i-2]+count[i-2](伪)里找max。
我们将数据先存进count,count[某个数]=该数之和,建立映射关系,如果选了这个数,那么这个数-1/+1就不都不能选,相当于不能连续选的意思,接下来用这个数组取填dp表就行了。
#include
using namespace std;
const int N=1e5+1;
int arr[N],count[N],dp[N];
int main() {
int n;cin>>n;
for(int i=0;i>arr[i];
count[arr[i]]+=arr[i];
}
for(int i=2;i<=10001;++i)
{
dp[i]=max(dp[i-1],dp[i-2]+count[i-1]);
}
cout<
七*?、平方数(数学)


这题没做出来,感觉自己废了。。。。
我现在在怀疑是不是int范围太小所以平方后溢出的问题,做的时候没有考虑这点忘记开longlong了
也有可能是二分判断时,mid*mid会溢出的问题,应该把其中一个mid除到另一边。唉修改了很多还是只能到百分之80.还是用sqrt函数吧服了
这里我又不服又试了新的解法,还是错了,算了老实用sqrt吧
sqrt(x); #include<cmath>
#include
#include
using namespace std;
typedef long long LL;
int main(){
LL x;
cin>>x;
LL a=sqrt(x);
LL x1=a*a,x2=(a+1)*(a+1);
if(x2-x>x-x1) cout<
八?、分组(枚举+二分)

完全没思路X﹏X
看完解答后感觉是很有意思的二分题。
如果我们知道了最终的人数最多的小组的人数x,那么对于每个声部的人假设有a人可以分成
a/x+(a%x==0?0:1)组,然后计算所有声部总和是不是等于m即可。所以这种找值的题目先想想暴力是怎么做的,然后再思考更优解吧~~~~~~
从这点上进行二分,我们将二分修改左右边界的判断条件写成一个函数
#include
#include
using namespace std;
const int N=1e5+1;
int arr[N],n,m,hmax;
bool check(int mid,unordered_map hash)
{
int groups=0;
for(auto&[x,y]:hash)
{
groups+=(y/mid+(y%mid==0?0:1));
}
return groups<=m;
}
int main()
{
unordered_map hash;
cin>>n>>m;
for(int i=0;i>arr[i];
++hash[arr[i]];
if(hash[arr[i]]>hmax)hmax=hash[arr[i]];
}
int kinds=hash.size(),ret=0;
if(kinds>m)cout<<-1;
else
{
int left=1,right=hmax;
while(left
九*、【模板】拓扑排序(建图+多源bfs)

建图+多源bfs
说起来多源bfs解决拓扑排序系列最近才总结了,做题的有意识要用bfs但是已经忘记如何建图了,无命休矣。
原多源bfs解决拓扑排序,建图过程:unordered_map<int,vector<int>> hash :key->value
然后还需要额外创建一个数组统计入度,因为每层bfs我们处理的都是入度为0的点,开始bfs前先将所有入度为0的源点入队,然后每层dfs,取完队头元素,将队头元素指向的所有结点入度减去1,如果有变成入度为0的

最后return检查是不是还有入度为0的点,如果有就是有环,该题的话就是返回-1

复习完多源bfs解决拓扑排序,现在看看该题具体该如何解答,按照这个思路也是可行的开始写代码吧!
#include
#include
#include
#include
using namespace std;
const int N=2e5+1;
int in[N];//处理入度
int main() {
int n,m;
cin>>n>>m;
//建图
unordered_map> hash;
int x,y;
while(m--)
{
cin>>x>>y;
hash[x].push_back(y);
++in[y];
}
//入度为0的点入队
queue q;
for(int i=1;i<=n;++i)
{
if(in[i]==0)q.push(i);
}
//bfs
vector ret;
while(!q.empty())
{
int t=q.front();
ret.push_back(t);
q.pop();
for(auto&x:hash[t])
{
if(--in[x]==0)q.push(x);
}
}
//检查是否有环
// for(int i=1;i<=n;++i)
// {
// if(in[i])
// {
// cout<<-1;
// break;
// }
// }
//其实也可以按照ret。size判断
if(ret.size()!=n)cout<<-1;
else
{
for(int i=0;i
明天继续加油o(* ̄︶ ̄*)o
书接上回~今天三道题都做出来了很开心哈哈
十、字符串替换(模拟)

很轻松的一道题
#include
class Solution {
public:
string formatString(string str, vector& arg) {
string ret;
int cur1=0,cur2=0;
while(cur1
十一*、神奇数(固定长度全排列)

其实全排列用嵌套for循环就能直接实现了
标答,看来质数判断得学习一下
#include
#include
#include
using namespace std;
bool isprimenum(int x){//判断该数是否是质数 用试除法
if(x<2||x%2==0) return false;//偶数肯定不是质数
int n=sqrt(x);
for(int i=3;i<=n;i+=2)//奇数除以偶数肯定不能整除
if(x%i==0) return false;
return true;
}
bool check(int x){//判断是否是神奇数
vector nums;
while(x){
nums.emplace_back(x%10);
x/=10;
}
int n=nums.size();
for(int i=0;i>a>>b;
int ret=0;
for(int i=max(10,a);i<=b;++i)
if(check(i)) ++ret;
cout<
本人写的
#include
#include
using namespace std;
const int N=1e5+1;
bool check[N];
int add,sum;
string path;
bool isPrime(int num)
{
bool flag=true;
for(int i=2;i>a>>b;
for(int i=a;i<=b;++i)
{
add=0;
//如果是神奇数,add置为1
isRightNum(to_string(i));
sum+=add;
}
cout<
十二、DNA序列(定长滑动窗口)


写得和标答一样,不愧是我
#include
#include
using namespace std;
int main() {
string s;int n;
cin>>s>>n;
//不能写等于,不然会输出两次s,一直没检查出来服了hhh
if(n>s.size())cout<max)
{
max=count;
begin=left;
}
}
while(rightmax)
{
max=count;
begin=left;
}
}
cout<
十三、小乐乐改数字(模拟)

#include
#include
using namespace std;
int main() {
int n;
cin>>n;
string s=to_string(n);
for(int i=0;i
十四、十字爆破(模拟)


牛牛咱下次别玩这么危险的游戏了好吗
long long格式化输出占位符是lld,不是d我服了。
#include
#include
using namespace std;
int main() {
int n,m;
cin>>n>>m;
vector> arr(n,vector(m));
vector row(n);
vector col(m);
for(int i=0;i
十五、比那名居的桃子(定长滑动窗口)


我服了,一直过不了,结果是int溢出了,以后遇到要算术运算操作的都开long long
#include
#include
using namespace std;
int main() {
int n, k;
cin >> n >> k;
vector a(n), b(n);
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; ++i) cin >> b[i];
long long happy = 0, embrassment = 0;
for (int i = 0; i < k; ++i) {
happy += a[i];
embrassment += b[i];
}
long long maxHappy = happy, minEmbra = embrassment;
int ret = 0;
int left = 0, right = k;
while (right < n) {
happy += a[right] - a[left];
embrassment += b[right] - b[left];
++right;
++left;
if (happy > maxHappy) {
maxHappy = happy;
minEmbra = embrassment;
ret = left;
}
else if (happy == maxHappy && embrassment < minEmbra) {
minEmbra = embrassment;
ret = left;
}
}
cout << ret + 1 << endl;
return 0;
}
十六、压缩字符串(一)

#include
class Solution {
public:
string compressString(string param) {
string ret;
int cur=1,n=param.size(),count;
if(n==0||n==1)return param;
while(cur1)ret+=to_string(count);
++cur;
}
//cur==n,末尾的没加上,如果末尾的加上了cur==n+1
if(cur==n)
{
ret+=param[cur-1];
if(count>1)ret+=to_string(count);
}
return ret;
}
};
十七、chika和蜜柑(重写排序,自定义比较规则)


自定义比较方法
#include
#include
#include
using namespace std;
#include
#include
using LL=long long;
struct cmp{
bool operator()(pair&a,pair&b)
{
//相等酸度降序排序
if(a.first==b.first)return a.second>b.second;
//按照甜度,升序排序
return a.first>n>>k;
vector Sour(n),Sweet(n);
for(int i=0;i>Sour[i];
for(int i=0;i>Sweet[i];
//key:Sweet[i]->value:Sour[i]
vector> Bind(n);
for(int i=0;in-1-k;--i)
{
SweetSum+=Bind[i].first;
SourSum+=Bind[i].second;
}
cout<
十八*、01背包

已经忘了背包问题怎么写了。。。。

短短几行代码,看来要复习复习背包问题了/(ㄒoㄒ)/~~
class Solution {
public:
int dp[1010]={0};
int knapsack(int V, int n, vector >& vw) {
//体积不超过V的情况下 当前能够装下的最大重量
//dp[i][j]表示从前i个物品选,体积不超过j的最大重量
for(int i=0;i=vw[i][0];--j)
dp[j]=max(dp[j],dp[j-vw[i][0]]+vw[i][1]);
return dp[V];
}
};
本周笔试完结撒花!!!
浙公网安备 33010602011771号