1🐋🐋🐋运动会进行中(钻石;前缀和)
时间限制:1.3秒
占用内存:128M
🐟题目描述
🐟输入输出格式
🐟样例
🐟题目思路
我们令-1表示女生、1表示男生,这样,如果某一区间内女生和男生的数量相等,那么求和将为0。
我们使用前缀和做这道题,用l[i]表示前缀和i出现的起始位置,r[i]表示前缀和i出现的末端位置,这说明,l[i]到r[i]区间内男女生数量相等,由此得出最大差值就是我们要的结果。
🐟代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,a[N],sum[N],l[2*N],r[2*N],ans;
int main( )
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]==0) a[i]=-1;
sum[i]=sum[i-1]+a[i];//求前缀和
int tmp=sum[i]+n;//这里是保证其为正数,如果全部都是女生,那么前缀和将为-n
if(!l[tmp]) l[tmp]=i;//前缀和tmp还没有左起点
else r[tmp]=i;//前缀和tmp有左起点了,记录其右起点
}
for(int i=0;i<2*n;i++) ans=max(ans,r[i]-l[i]);
cout<<ans<<endl;
return 0;
}
2🐋🐋🐋矩阵01变(黄金;前缀和)
时间限制:1秒
占用内存:128M
🐟题目描述
🐟输入输出格式
🐟样例
🐟题目思路
前缀和的经典题目。
其实就是输出每个位置之前(xy为右下角的矩阵)的所有1的个数。
我们使用数组sum记录位置xy的前缀和。
🐟代码
#include<bits/stdc++.h>
using namespace std;
char a[110][110];
int b[110][110],sum[110][110];
int n,m;
int main( )
{
cin>>n>>m;
//输入
for(int i=1;i<=n;i++) scanf("%s",a[i]+1);
//将输入处理成int型数据
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]=='1') b[i][j]=1;
}
}
//计算前缀和
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+b[i][j];//前缀和
}
}
//输出
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cout<<sum[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
3🐋🐋🐋AK IOI(钻石;反悔贪心)
时间限制:1秒
占用内存:128M
🐟题目描述
🐟输入输出格式
🐟样例
🐚样例
🐚备注
🐟题目思路
选择某些达到什么状态,典型的贪心算法题目,这里涉及到最优情况,我们考虑用反悔贪心算法。(想要多看看练练贪心算法的同学可以看一下另一篇博客码蹄集部分题目(2024OJ赛13期;贪心集训+递归集训)_小明oj 2024年4月赛题解-CSDN博客)
这次我们使用最大堆,由于到达某个x的路程时间是固定的,所以我们只需要判断t需不需要反悔即可。所以我们先按x将各点排序,然后遍历他们,判断“到达该点+AK”是否满足时间限制,如果满足就将t入堆;如果不满足,就要判断是否需要反悔,如果去掉最大t的AK,然后到达当前位置并加上当前AK可以满足时间限制,那么就反悔。
最后堆中点的个数就是我们要的答案。
🐟代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+10;
struct node
{
ll x,t;
}a[N];
ll n,m,sum,ans;//sum记录的是到目前为止AK的t的大小,因为x只需要在最后加一次
priority_queue<ll> q;//最大堆;走到某个x的时间是固定的,所以反悔的只是t,这个堆就只排t即可
bool cmp(node a,node b) {return a.x<b.x;}
int main( )
{
cin>>n>>m;
for(ll i=1;i<=n;i++) cin>>a[i].x>>a[i].t;
sort(a+1,a+1+n,cmp);//按位置排序
for(ll i=1;i<=n;i++)
{
if(sum+a[i].x+a[i].t<=m)//如果到这个地方进入并AK不会超过时间限制,那么这个地方就考虑进内
{
sum+=a[i].t;
q.push(a[i].t);
}
else if(!q.empty()&&sum-q.top()+a[i].x+a[i].t<=m)//现在不能再往里加了,要看看有没有需要反悔的
{
//如果减去最大的t,再加上当前的位置和t还满足时间限制,那么就反悔
sum-=q.top()+a[i].t;
q.pop();
q.push(a[i].t);
}
}
cout<<q.size()<<endl;
return 0;
}
4🐋🐋🐋新的表达式(星耀;栈)
时间限制:1秒
占用内存:128M
🐟题目描述
🐟输入输出格式
🐟样例
🐚样例
🐚备注
🐟题目思路
这道题目是栈的典型应用,但是其中有很多细节需要注意。
先总结下栈在运算式中的主要思路:
-
两个栈分别存放数字和操作
-
如果遇到“(”直接入操作栈
-
如果遇到“)”就需要进行计算操作,这个操作是要到遇到“(”才结束的,所以用while重复操作:从数字栈中拿出两个数字、从操作栈中拿出一个操作符,运算,然后数字压入数字栈。最后记得pop掉该组的“(”
这道题目的细节有如下几点:
-
由于&和|优先级相同,所以需要从左往右进行运算,那么就需要循环先判断两个操作的优先级(我们这里人为定义&和|优先级为1,括号优先级为-1,这是为了方便操作),如果栈中的优先级大或者相等的话,前边那个(也就是栈里的操作符)先计算,直到前边没有比我更大的操作符了,我这个&或|再加入栈
-
多位数字的处理,就用一个while找出一个数就可以,这里用isdigit(s[i])函数来判断s[i]是否为数字
🐟代码
#include<bits/stdc++.h>
using namespace std;
int priority(char op)
{
if(op=='&'||op=='|') return 1;
else return -1;
}
void calculate(stack<int> &st,char op)
{
int a=st.top();
st.pop();
int b=st.top();
st.pop();
if(op=='&') st.push(min(a,b));
else st.push(max(a,b));
}
int work(string &s)
{
stack<int> st;
stack<char> op;
for(int i=0;i<s.size();i++)
{
if(s[i]=='(') op.push('(');
else if(s[i]==')')
{
while(op.top()!='(')
{
calculate(st,op.top());
op.pop();
}
op.pop();//pop掉(
}
else if(s[i]=='&'||s[i]=='|')
{
char cur=s[i];
while(!op.empty()&&priority(op.top())>=priority(cur))//保证从左往右运算
{
calculate(st,op.top());
op.pop();
}
op.push(cur);
}
else{
int num=0;
while(i<(int)s.size()&&isdigit(s[i])) num=num*10+s[i++]-'0';
i--;
st.push(num);
}
}
while(!op.empty())
{
calculate(st,op.top());
op.pop();
}
return st.top();
}
int main( )
{
string s;
cin>>s;
cout<<work(s)<<endl;
return 0;
}
5🐋🐋🐋算术招亲(星耀;栈)
时间限制:2秒
占用内存128M
🐟题目描述
🐟输入输出格式
🐟样例
🐚样例
🐚备注
🐟题目思路
这道题目也是一道典型的栈用作算式运算的题目,与上道题目思路一致,这里强调要注意-和/的a和b的顺序。
🐟代码
#include<bits/stdc++.h>
using namespace std;
const int N=40;
bool tag[N];
bool isop(char c) {return c=='+'||c=='-'||c=='*'||c=='/'||c=='^';}
int priority(char op)
{
if(op=='+'||op=='-') return 1;
if(op=='*'||op=='/') return 2;
if(op=='^') return 3;
return -1;
}
void calculate(stack<int> &st,char op)
{
int a=st.top();
st.pop();
int b=st.top();
st.pop();
if(op=='+') st.push(a+b);
else if(op=='-') st.push(b-a);
else if(op=='*') st.push(a*b);
else if(op=='/') st.push(b/a);
else st.push(pow(b,a));
//cout<<st.top()<<endl;//
}
int work(string &s)
{
stack<int> st;
stack<char> op;
for(int i=0;i<(int)s.size();i++)
{
if(s[i]=='(')
{
if(!tag[i]) continue;
op.push('(');
}
else if(s[i]==')')
{
if(!tag[i]) continue;
while(op.top()!='(')
{
calculate(st,op.top());
op.pop();
// cout<<st.top()<<endl;//
}
op.pop();//pop掉(
}
else if(isop(s[i]))
{
char cur=s[i];
while(!op.empty()&&priority(op.top())>=priority(cur))
{
calculate(st,op.top());
op.pop();
//cout<<st.top()<<endl;//
}
op.push(cur);
}
else
{
int num=0;
while(i<(int)s.size()&&isdigit(s[i])) num=num*10+s[i++]-'0';
i--;
st.push(num);
//cout<<st.top()<<endl;//
}
}
while(!op.empty())
{
calculate(st,op.top());
op.pop();
//cout<<st.top()<<endl;//
}
return st.top();
}
void init(string &s)//记录多余小括号
{
stack<pair<char,int> > st;
for(int i=0;i<s.size();i++)
{
if(!st.empty()&&st.top().first=='('&&s[i]==')')
{
tag[i]=tag[st.top().second]=true;
st.pop();
}
else if(s[i]=='(') st.push({'(',i});
}
}
int main( )
{
string s;
cin>>s;
init(s);
cout<<work(s)<<endl;
return 0;
}
6🐋🐋🐋环形喂猪(星耀;反悔贪心)
时间限制:1.5秒
占用内存:250M
🐟题目描述
🐟输入输出格式
🐟样例
🐚样例
🐚备注
🐟题目思路
这道题目还是反悔贪心,贪心是说,我们每次都喂饥饿值最大的那头猪,反悔是说,如果喂它左右的猪不喂它反而获得的饥饿值更大,那么我们就反悔。
这里重新更新左右邻的地方我不太懂,欢迎懂的大佬评论区解答一下~
🐟代码
#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
bool vis[200010];
struct P//猪,饥饿值和左右邻
{
int val,l,r;
}p[200010];
struct node//饥饿值以及对应的猪所在的位置
{
int val,id;
bool operator<(node it) const {return val<it.val;}
};
priority_queue<node> q;//使用最大堆,每次头部的是最大饥饿值的猪
int main( )
{
int n,m;
cin>>n>>m;
if(m>n/2)//不能喂相邻的,所以如果m>n/2,那么m袋无法喂完,因为一共最多能喂n/2只猪
{
cout<<"Error!";
return 0;
}
for(int i=1;i<=n;i++)
{
cin>>p[i].val;
p[i].l=i-1;
p[i].r=i+1;
q.push((node){p[i].val,i});
}
p[1].l=n;
p[n].r=1;
for(int i=1;i<=m;i++)
{
while(vis[q.top().id]) q.pop();
node now=q.top();
q.pop();
vis[p[now.id].l]=vis[p[now.id].r]=1;//标记当前猪的左右邻都被判断过了
p[now.id].val=p[p[now.id].l].val+p[p[now.id].r].val-p[now.id].val;
q.push((node){p[now.id].val,now.id});//把新情况加入堆
ans+=now.val;
//更新左右邻,这部分有点没懂,欢迎大佬们在评论区解答~
p[now.id].l=p[p[now.id].l].l;
p[now.id].r=p[p[now.id].r].r;
p[p[now.id].l].r=now.id;
p[p[now.id].r].l=now.id;
}
cout<<ans<<endl;
return 0;
}
有问题我们随时评论区见~
⭐点赞收藏不迷路~