P1198 [JSOI2008]最大数

题目传送门

多姿多彩的做法

暴力(非正解)

暴力还是很好打的。整体时间复杂度为 \(O(ml)\) (极端情况,\(l\) 为数列长度)。

线段树

考试的时候本来想这么写的,可是写挂了,我太弱了。

由于初始集合是 \(0\) ,我们不需要写性能瓶颈(时间复杂度 \(O(m\log m)\))的建树,只需要写维护最大值(记得取模)的单点修改与区间查询就成。

整体时间复杂度为 \(O(m \log m)\)

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

int t[800005];
int m,d;
char op;
int x,tt,cnt;

void pushup(int i){
	t[i]=max(t[i<<1],t[i<<1|1])%d;
}
void update(int pv,int v,int i,int l,int r){
	if(l==r){
		t[i]=v;
		return;
	}
	int mid=(l+r)>>1;
	if(mid>=pv){
		update(pv,v,i<<1,l,mid);
	}
	if(mid<pv){
		update(pv,v,i<<1|1,mid+1,r);
	}
	pushup(i);
}

int ask(int ql,int qr,int i,int l,int r){
	if(ql<=l&&qr>=r){
		return t[i];
	}
	int mid=(l+r)>>1;
	int result=LLONG_MIN;
	if(ql<=mid){
		result=max(result,ask(ql,qr,i<<1,l,mid));
	}
	if(qr>mid){
		result=max(result,ask(ql,qr,i<<1|1,mid+1,r));
	}
	return result;
}

signed main(){
	cin>>m>>d;
	for(int i=1;i<=m;i++){
		cin>>op>>x;
		if(op=='A'){
			update(cnt+1,(x+tt)%d,1,1,m);
			cnt++;
		}
		else{
			if(x==0)tt=0;
			else tt=ask(cnt-x+1,cnt,1,1,m)%d;
			cout<<tt<<endl;
		}
	}
	return 0;
}

Record

单调栈+单调栈上二分

由于只查询最后几个元素,因此只要建两个单调栈,一个维护值,一个维护位置。然后二分找下标。

整体时间复杂度为 \(O(m \log m)\)

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

int m,t,d;
int sta[3][200005],top,cnt;

void push(int k){
	cnt++;
	while(k>sta[1][top]&&top>0){
		top--; // Pop if it's smaller than the element it will be push
	}
	sta[0][++top]=cnt;
	sta[1][top]=k;
}

bool check(int x,int v){
	return sta[0][x]<v;
}
int binarySearch(int v,int l,int r){ // Binary Search(Lower Bound)
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid,v)){
			l=mid+1;
		}
		else{
			r=mid;
		}
	}
	t=sta[1][r];
	return t;
}

signed main(){
	cin>>m>>d;
	for(int i=1;i<=m;i++){
		char op;int x;
		cin>>op>>x;
		if(op=='A'){
			push((t+x)%d);
		}
		else{
			cout<<binarySearch(cnt-x+1,1,top)<<endl;
		}
	}
	return 0;
}

Record

ST表

参考自这里

这里的ST表 \(f[i][j]\) 维护的是区间 \(a[i,i-(2^j)+1]\) 的最值。

ST表可以维护RMQ问题,本问题可以用ST表解答,插入不会影响原来的ST表。

时间复杂度还是熟悉的 \(O(m \log m)\)

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

int a[200005],f[200005][25],t,d,n,m;

void change(int u){  
    f[u][0]=a[u];
    for(int i=1;u-(1<<i)>=0;i++){
    	f[u][i]=max(f[u][i-1],f[u-(1<<(i-1))][i-1]);
	}
}
int find(int x,int y){
    double t=log(y-x+1)/log(2);
    int K=t;
    return max(f[y][K],f[x+(1<<K)-1][K]);
}

signed main(){
	cin>>m>>d;
	for(int i=1;i<=m;i++){
		char c;int x;
		cin>>c>>x;
		if(c=='A'){
			a[++n]=(x+t)%d; // it's simliar than BF algorithm
			change(n);
		}
		else{
			int ans;
			if(ans==1){
				cout<<a[n]<<endl;
				t=a[n];
			}
			else{
				ans=find(n-x+1,n);
				cout<<ans<<endl;
				t=ans;
			}
		}
	}
	return 0;
}

Record

单调队列+单调队上二分

考虑维护一个单调队列,维护以最后一个数结束的极大值。

插入数字=入队

接着二分查询执行查询操作。

整体时间复杂度为 \(O(m \log m)\)

这里写的是std::lower_bound(不想粘贴二分模板)。

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

int a[200005],q[200005];
int m,d,head,tail,t;

signed main(){
	cin>>m>>d;
	for(int i=1;i<=m;i++){
		char op;int x;
		cin>>op>>x;
		if(op=='A'){
			a[++head]=(x+t)%d;
			while(tail>0&&a[q[tail-1]]<a[head]){
				tail--;
			}
			q[tail++]=head;
		}
		else{
			cout<<(t=a[*lower_bound(q,q+tail,head-x+1)])<<endl;
		}
	}
	return 0;
}

Record

单调队列+并查集维护下标

其实只要维护一个集合(可以用并查集实现),存储下标,找根即可。

出队时合并集合。

使用路径压缩优化并查集,整体时间复杂度 \(O(m \log m)\),一般为 \(O(m\alpha(m))=O(m)\)。可以说是线性的。

注意:不能按秩合并,会全WA的!

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

int a[200005],q[200005];
int m,d,head,tail,t;

int fa[200005];
//int Rank[200005];
int find(int x){
	if(fa[x]==x)return x;
	else return fa[x]=find(fa[x]);
}
int merge(int x,int y){
	int a=find(x),b=find(y);
	fa[a]=b;
}

signed main(){
	srand(time(0));
	cin>>m>>d;
	for(int i=1;i<=m;i++){
		char op;int x;
		cin>>op>>x;
		if(op=='A'){
			a[++head]=(x+t)%d;
			fa[head]=head;
			//Rank[head]=rand();
			while(tail>0&&a[q[tail-1]]<a[head]){
				merge(q[tail-1],head);
				tail--;
			}
			q[tail++]=head;
		}
		else{
			cout<<(t=a[find(head-x+1)])<<endl;
		}
	}
	return 0;
}

Record

posted @ 2022-02-09 15:09  蒟蒻xiezheyuan  阅读(37)  评论(0编辑  收藏  举报