2024/3/2 AT_abc343 做题记录

本文记录了一位参赛者在编程竞赛中的经历,包括遇到的难题(如翻译软件导致的错误),解决策略(如A题的翻译问题,D题使用STL,F题的分块和线段树思路),以及时间复杂度分析。
摘要由CSDN通过智能技术生成

这个人 CSP-S 接近保单,NOIP 没参加,所以自然参加不了省选,只能打 abc 涨信心。

19:00

赛前看个新闻联播,放松身心~

19:38

赛前想做出来 P10143,结果发现实力不允许。

20:00

启动!

20:01 A题

ABC 特产,A题一眼得不能再一眼,但我事先没有打开翻译软件,寄飞了……开赛两分半才做出 A 题

20:03 B题

直接做题,甚至都不用开数组,直接输入的时候输出……

20:06 干出来了。

20:06 C题

这个翻译软件我服了啊,多出来这么多换行,害得我改格式改了五分钟。

然后我又看了五分钟的题目,发现 n ≤ 1 0 18 n \leq 10^{18} n1018,看上去很唬人,但实际上答案是 1 0 6 10^6 106 以内的某个数的完全立方数,直接枚举底数就行了,判断回文数也十分简单粗暴,用数组记录每一位就行了。至于答案上界,就是 n 3 \sqrt[3]{n} 3n ,可以直接用二分法求。

时间复杂度: O ( n 3 log ⁡ 10 n ) O(\sqrt[3]{n} \log_{10}{n}) O(3n log10n)

代码

#include <cstdio>
using namespace std;
long long n,l,r,mid;
int a[20],tot;
bool hui(long long p){
	tot=0;
	while(p)a[++tot]=p%10,p/=10;
	for(int i=1;i<=tot>>1;++i)if(a[i]!=a[tot-i+1])return 0;
	return 1;
}
int main(){
	scanf("%lld",&n),l=1,r=1000000;
	while(l<=r){
		mid=l+r>>1;
		if(mid*mid*mid>n)r=mid-1;
		else l=mid+1;
	}--l;
	for(;l;--l)if(hui(l*l*l))return 0*printf("%lld",l*l*l);
}

20:24 才做出来,主要是第八行的 a[tot-i+1] 写成了 a[n-i+1],警钟长鸣。

20:24 D题

再次吐槽翻译软件。

看了十分钟题目才看出来,我是飞五。

这题用 STL 乱搞就行了。用数组维护每个人当前的得分,用 map 维护每个分数对应多少人,用 set 维护当前有多少种不同的得分。唯一的注意点是要开 long long

时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn)

代码

#include <bits/stdc++.h>
using namespace std;
int n,t,x,y;
long long a[200001];
map<long long,int>mp;
set<long long>s;
int main(){
	scanf("%d%d",&n,&t),mp[0]=n,s.insert(0);
	for(int i=1;i<=t;++i){
		scanf("%d%d",&x,&y);
		if(!--mp[a[x]])s.erase(a[x]);
		a[x]+=y,s.insert(a[x]),++mp[a[x]],printf("%d\n",s.size());
	}return 0;
}

20:41 完成。

20:41 E题

切这题以前我看了一下榜,好家伙 E 过的人 怎么比 F 还少?再看了一眼题目,好像是暴力。死推结论失败了,只能去看看 F。

21:20 F题

首先,看翻译花了五分钟。。。

由于我实在太蒟蒻了,不会用线段树之类的高级数据结构,当时就心血来潮想用分块,可是时间原因,比完赛才打完操作一。所以赛后继续搞。

考虑 O ( n q ) O(nq) O(nq) 暴力怎么做:询问区间内维护最大值、次大值、最大值数量、次大值数量。

那我们分块的做法也类似,先预处理一开始每个块内的最大值等信息,然后该怎么做怎么做。

好在 22:58 的时候,WA 了三次终于 AC 了……

细节挺多的,直接上代码了吧。

时间复杂度: O ( q n + n ) O(q \sqrt n +n) O(qn +n)。这里为了方便,我直接令块长为 500 500 500,时间复杂度差不多。

代码

#include <cstdio>
using namespace std;
int a[401][501],zd[401],cd[401],zdcnt[401],cdcnt[401],n,q,tot,res,op,l,r,now,l1,l2,r1,r2,retzd,retcd,retzdcnt,retcdcnt;
int main(){
	scanf("%d%d",&n,&q);for(int i=1;i<=n;++i)scanf("%d",&a[(i-1)/500+1][(i-1)%500+1]);
	tot=(n-1)/500+1,res=(n-1)%500+1;
	for(int i=1;i<tot;++i){
		for(int j=1;j<501;++j){
			if(a[i][j]>zd[i])cd[i]=zd[i],cdcnt[i]=zdcnt[i],zd[i]=a[i][j],zdcnt[i]=1;
			else if(a[i][j]==zd[i])++zdcnt[i];
			else if(a[i][j]>cd[i])cd[i]=a[i][j],cdcnt[i]=1;
			else if(a[i][j]==cd[i])++cdcnt[i];
		}
	}
	for(int j=1;j<=res;++j){
		if(a[tot][j]>zd[tot])cd[tot]=zd[tot],cdcnt[tot]=zdcnt[tot],zd[tot]=a[tot][j],zdcnt[tot]=1;
		else if(a[tot][j]==zd[tot])++zdcnt[tot];
		else if(a[tot][j]>cd[tot])cd[tot]=a[tot][j],cdcnt[tot]=1;
		else if(a[tot][j]==cd[tot])++cdcnt[tot];
	}
	while(q--){
		scanf("%d%d%d",&op,&l,&r);
		if(op==1){now=(l-1)/500+1,a[now][(l-1)%500+1]=r,zd[now]=cd[now]=zdcnt[now]=cdcnt[now]=0;
			if(now==tot){
				for(int j=1;j<=res;++j){
					if(a[tot][j]>zd[tot])cd[tot]=zd[tot],cdcnt[tot]=zdcnt[tot],zd[tot]=a[tot][j],zdcnt[tot]=1;
					else if(a[tot][j]==zd[tot])++zdcnt[tot];
					else if(a[tot][j]>cd[tot])cd[tot]=a[tot][j],cdcnt[tot]=1;
					else if(a[tot][j]==cd[tot])++cdcnt[tot];
				}
			}else{
				for(int j=1;j<501;++j){
					if(a[now][j]>zd[now])cd[now]=zd[now],cdcnt[now]=zdcnt[now],zd[now]=a[now][j],zdcnt[now]=1;
					else if(a[now][j]==zd[now])++zdcnt[now];
					else if(a[now][j]>cd[now])cd[now]=a[now][j],cdcnt[now]=1;
					else if(a[now][j]==cd[now])++cdcnt[now];
				}
			}
		}
		if(op==2){l1=(l-1)/500+1,l2=(l-1)%500+1,r1=(r-1)/500+1,r2=(r-1)%500+1,retzd=retcd=retzdcnt=retcdcnt=0;
			if(l1==r1){
				for(int i=l2;i<=r2;++i){
					if(a[l1][i]>retzd)retcd=retzd,retcdcnt=retzdcnt,retzd=a[l1][i],retzdcnt=1;
					else if(a[l1][i]==retzd)++retzdcnt;
					else if(a[l1][i]>retcd)retcd=a[l1][i],retcdcnt=1;
					else if(a[l1][i]==retcd)++retcdcnt;
				}
			}else{
				for(int i=l2;i<501;++i){
					if(a[l1][i]>retzd)retcd=retzd,retcdcnt=retzdcnt,retzd=a[l1][i],retzdcnt=1;
					else if(a[l1][i]==retzd)++retzdcnt;
					else if(a[l1][i]>retcd)retcd=a[l1][i],retcdcnt=1;
					else if(a[l1][i]==retcd)++retcdcnt;
				}for(int i=l1+1;i<r1;++i){
					if(zd[i]>retzd)retcd=retzd,retcdcnt=retzdcnt,retzd=zd[i],retzdcnt=zdcnt[i];
					else if(zd[i]==retzd)retzdcnt+=zdcnt[i];
					else if(zd[i]>retcd)retcd=zd[i],retcdcnt=zdcnt[i];
					else if(zd[i]==retcd)retcdcnt+=zdcnt[i];
					if(cd[i]>retcd)retcd=cd[i],retcdcnt=cdcnt[i];
					else if(cd[i]==retcd)retcdcnt+=cdcnt[i];
				}
				for(int i=1;i<=r2;++i){
					if(a[r1][i]>retzd)retcd=retzd,retcdcnt=retzdcnt,retzd=a[r1][i],retzdcnt=1;
					else if(a[r1][i]==retzd)++retzdcnt;
					else if(a[r1][i]>retcd)retcd=a[r1][i],retcdcnt=1;
					else if(a[r1][i]==retcd)++retcdcnt;
				}
			}printf("%d\n",retcdcnt);
		}
	}
	return 0;
}

G题我就看了一眼,不会做,所以就先咕咕咕着吧……

orz AK dalao。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值