ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022.7.13 模拟赛

2022-07-13 19:02:51  阅读:114  来源: 互联网

标签:13 ch int max cdot while 2022.7 模拟 getchar


目录

2022.7.13 模拟赛

\(\to\text{link}\leftarrow\)

最大序列

思路

首先出栈的必然是最大的数

设每次出栈的数在 \(i\) 处

然后不断比较 \(i-1\) 处的数和 \(i\sim n\) 中最大的数,判断往哪边出栈

细节很多 貌似就只有我一个人写了76行的代码,其余人都是30多行

#include<bits/stdc++.h>
using namespace std;

const int N=2e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,now;
int a[N],b[N];
int f[N],l[N],g[N];
bool vis[N];

inline int find(int x){
	return l[x]==x?x:l[x]=find(l[x]);
}

inline int get(int x){
	return g[f[x]]==1?f[x]=get(f[x]):f[x];
}

signed main(){
	n=read();
	for(int i=1;i<=n;++i){
		a[i]=read();
		b[a[i]]=i;
		if(a[i]==n) now=i,vis[i]=1;
	}
	int mx=n;
	f[n]=g[n]=n;
	for(int i=n-1;i;--i){
		f[i]=g[i]=mx;
		if(a[i]>a[mx])
			mx=i;
	}
	int cnt=0;
	printf("%d ",n);
	a[n+1]=a[n+2]=1e9;
	for(int i=1;i<=n;++i) l[i]=i;
	l[b[n]]=b[n]-1;
	g[b[n]]=1;
	while(cnt<n-1){
		if(now==n) break;
		if(find(now)==0){
			now=get(now);
			printf("%d ",a[now]);
			vis[now]=1;
			l[now]=find(now-1);
			g[now]=1;
			++cnt;
			continue;
		}
		int x=a[get(now)],y=a[find(now)];
		//cout<<x<<" "<<y<<endl;
		if(y<x){
			vis[b[x]]=1;
			printf("%d ",x);
			now=b[x];
			l[b[x]]=find(b[x]-1);
			g[now]=1;
		}
		else{
			vis[b[y]]=1;
			printf("%d ",y);
			now=b[y];
			l[now]=find(now-1);
			g[now]=1;
		}
		++cnt;
	}
	for(int i=n;i;--i) if(!vis[i]) printf("%d ",a[i]);
}

调了 \(1h\) \(qaq\)

思考熊的马拉松

这个题实际上是把速度 \(a_{1\sim n}\) 从小到大排序,然后求:

\[\sum_{i=1}^{n}\sum_{j=1}^{i-1}\left \lfloor \frac{(a_i-a_j)\cdot L}{a_{max}} \right \rfloor \]

首先考虑 \(a_{max}|L\) 的部分分

这部分 \(\frac L{a_{max}}\) 实际上可以当作一个常数 \(k\),可以考虑将其提出来然后求的式子就变成了:

\[k\cdot\sum_{i=1}^{n}\sum_{j=1,a_j<a_i}^{n}(a_i-a_j) \]

考虑每个数的贡献,容易得到第 \(i\) 个数的贡献是由两部分 \(i-1\) 和 \(-(n-i)\) 组成,所以贡献为 \(i-1-(n-i)=2\cdot i-1-n\)

这个做法给了我们满分的启示:统计每一个数的贡献

但由于原式要向下取整,所以分类讨论

假设 \(b_i=(a_i\cdot L)\bmod a_{max}\),那么:

  • 当 \(b_i\ge b_j\) 时,\(\left \lfloor \frac{(a_i-a_j)\cdot L}{a_{max}} \right \rfloor=\left \lfloor \frac{a_i\cdot L}{a_{max}} \right \rfloor-\left \lfloor \frac{a_j\cdot L}{a_{max}} \right \rfloor\)

  • 当 \(b_i<b_j\) 时,\(\left \lfloor \frac{(a_i-a_j)\cdot L}{a_{max}} \right \rfloor=\left \lfloor \frac{a_i\cdot L}{a_{max}} \right \rfloor-\left \lfloor \frac{a_j\cdot L}{a_{max}} \right \rfloor-1\)

化简之后的式子中的两个部分都可以按照贡献统计,然后还要减去 \(i>j\) 且 \(b_i<b_j\) 的部分

这不就是逆序对吗?采用归并排序求逆序对

此题做完了,时间复杂度 \(O(T\cdot n\log n)\)

#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=2e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,A,L,mx,num;
int a[N],s[N],b[N],tmp[N];

inline void doge(){
	int ans=0;
	for(int i=n;i;--i){
		ans+=1ll*(i-1)*a[i]-s[i-1];
	}
	cout<<ans*(L/mx)<<endl;
}

inline void merge(int l,int r){
	if(l==r) return;
	int mid=l+r>>1;
	merge(l,mid),merge(mid+1,r);
	int i=l,j=mid+1,cnt=l-1;
	while(i<=mid&&j<=r){
		if(b[i]>b[j]) num+=mid-i+1,tmp[++cnt]=b[j++];
		else tmp[++cnt]=b[i++];
	}
	while(i<=mid) tmp[++cnt]=b[i++];
	while(j<=r) tmp[++cnt]=b[j++];
	for(int i=l;i<=r;++i) b[i]=tmp[i];
}

inline void cat(){
	num=0;
	for(int i=1;i<=n;++i) b[i]=a[i]%mx*L%mx;
	merge(1,n);
	int res=0;
	for(int i=1;i<=n;++i){
		res+=(i*2-n-1)*((a[i]*L)/mx);
	}
	cout<<res-num<<endl;
}

inline void solve(){
	n=read(),A=read(),L=read();
	for(int i=1;i<=n;++i) a[i]=read();
	sort(a+1,a+n+1);
	mx=a[n];
	for(int i=1;i<=n;++i) s[i]=s[i-1]+a[i];
	if(L%mx==0) doge();
	else cat();
}

signed main(){
	int T=read();read();
	while(T--)
		solve();
}

疏散演习

这题是个玄学骗分题

我打了 \(30pts\) 的暴力然后走人

下标

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5;

#define next ijlkjdashadshfhauisehgfiawbesfdyhgwasdafiuhedsuafhuisagdiufgadsiufguidasgfiagw

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,top;
char s[N];
int cnt[N],st[N],next[N],match[N];

inline bool check(int l0,int r0,int l1,int r1){
	for(int i=l0,j=l1;;i=next[i],j=next[j]){
		if(s[i]!=s[j]) return s[i]<s[j];
		if(i==r0||j==r1) return i==r0;
	}
}

inline void solve(int &l,int r){
	if(isalpha(s[r])) return;
	int mid=match[r];
	int x=mid-1,y=mid+1,end=r--;
	solve(l,x);solve(y,r);
	if(!check(l,x,y,r)) swap(l,y),swap(x,r);
	next[x]=mid;
	next[mid]=y;
	next[r]=end;
}

inline void work(){
	scanf("%s",s);
	n=strlen(s);
	for(int i=0;i<n;++i) next[i]=i+1;
	cnt[0]=0;
	for(int i=0;i<n;++i) cnt[i+1]=cnt[i]+(!isalpha(s[i]));
	top=0;
	memset(match,-1,sizeof(match));
	for(int i=0;i<n;++i)
		if(s[i]=='[') st[top++]=i;
		else if(s[i]==']') match[i]=st[--top];
	int x=0;
	solve(x,n-1);
	for(int i=x;i<n;i=next[i]) cout<<s[i];
	cout<<endl;
}

signed main(){
	int T=read();
	while(T--) work();
}

标签:13,ch,int,max,cdot,while,2022.7,模拟,getchar
来源: https://www.cnblogs.com/into-qwq/p/16475186.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有