acwing 62周赛
第62场周赛心得
前面的周赛都没有记录,因为博客的原因。
切入正题
T1.三个元素
题面: 给定序列\(a_1,a_2,a_3,....,a_n\),请找出三个元素\(r_1,r_2,r_3\),使得\(r_1 < r_2 < r_3\) 。
\(T1\)一般是打卡题,这次虽然不出意外的和之前一样简单,但是因为是速度赛,所以在审题上马虎了。
简直简单的抠脚了,结果WA了一次…… 。
不说。
AC code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define in inline
#define rint register int
typedef long long LL;
typedef pair<int,int> PII;
in int read()
{
rint x=0,f=0; register char ch=getchar();
while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
/*----------code----------*/
const int N=1e5+10;
PII a[N];
int n,m,k;
int main()
{
n=read();
for(int i=1;i<=n;i++) a[i].first=read(),a[i].second=i;
sort(a+1,a+n+1);
int res=0;
vector<int> v;
for(int i=1;i<=n&&v.size()<=2;i++)
if(a[i].first>a[i-1].first) v.push_back(a[i].second);
if(v.size()<3) puts("-1 -1 -1");
else
for(int i=0;i<3;i++) cout<<v[i]<<' ';
return 0;
}
T2.收集卡牌
简化题面:
有\(n\)次操作,每次读入一个1~m的数,请问在每次操作之后,是否能集齐所有数字(1 ~ m)。
如果集齐并兑换了一次,那么兑换出去的卡牌就不属于你了(需要减去)。
请输出每一次操作后的状态(不能集齐就是0,能就是1)
样例:
3 11
2 3 1 2 2 2 3 2 2 3 1
输出:
00100000001
按照比赛经验,第二题应该是优化题(贪心,数据结构,前缀和差分等)。
这一题最初看到范围是十万,于是就想到\(O(n*log \ n)\)的做法。
又因为每个卡牌号1到m,所以想到了树状数组的做法。
后来又发现树状数组的方法会绕弯,那么转到\(O(n)\)。
线性做法发现这题直接暴力可以过(想不到吧)。
用哈希表存储每一个卡牌的数量,然后记录目前集齐了多少种卡牌。
算法是模拟,直接暴力:
AC code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define in inline
#define rint register int
typedef long long LL;
typedef pair<int,int> PII;
in int read()
{
rint x=0,f=0; register char ch=getchar();
while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
/*----------code----------*/
const int N=1e5+10;
int a[N];
int n,m,k;
int main()
{
m=read(),n=read();
for(int i=0;i<n;i++) a[i]=read();
string res="";
int cnt=0,st[N];
memset(st,0,sizeof st);
for(int i=0;i<n;i++)
{
if(!st[a[i]]) cnt++;
st[a[i]]++;
if(cnt==m)
{
res+='1';
for(int i=1;i<=m;i++)
if(!--st[i]) cnt--;
}
else res+='0';
}
cout<<res;
return 0;
}
T3.集合操作
题面已经最简,所以不再简化。
本题为计算题,考验数学分析能力。
数学证明分三个步骤,具体见这一篇题解
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define in inline
#define rint register int
typedef long long LL;
typedef pair<int,int> PII;
in int read()
{
rint x=0,f=0; register char ch=getchar();
while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
/*----------code----------*/
const int N=5e5+10;
int a[N];
int n=0,m,k;
int main()
{
m=read();
double res=0,sum=0;
while(m--)
{
int op=read();
if(op==1)
{
a[++n]=read();
while(k+1<=n&&a[k+1]<=(sum+a[n])/(k+1)) sum+=a[++k];
res=max(res,a[n]-(sum+a[n])/(k+1));
}
else printf("%.6lf\n",res);
}
return 0;
}
结尾
在文末添加一下自己的想法。
题目都不是很难,前两题小于等于普及组,第三题大于普及组,小于提高组。
诶,只能说多刷题培养灵感吧。
本文来自博客园,作者:{三季野花},转载请注明原文链接:https://www.cnblogs.com/SanGarden/articles/16535948.html