0
点赞
收藏
分享

微信扫一扫

2022 4.10模拟赛总结

三个点三道题。

先说一下考试过程。拿到题,先看了第一题,一道广搜,直接花了10分钟左右打完,调完,两个样例都过了。

然后去看T3,看样子是个分块,但没学过不会写。。又像一个线段树,但是不知道怎么维护。于是先暴力打了个部分分,T3先放在一边。

现在过了半个点吧大概,然后去看T2。嗯。。看样子是道动态规划,又像一道模拟。题目给的条件也很简单,在纸上推了一会式子,把最优解给想出来。看了数据范围,n^{2}动态规划应该就行了吧。打完了试了样例,也过了。

最后回去看T3,本来想交暴力的,卡卡常,颓了一会。又发现线段树好像也能写,每次维护最大值和最小值就行了。(啊啊啊mid一定是l+r>>1,手残把l写成1调了好长时间)。样例过了,但不知道能不能过吧。。

T1

 

一道很水的广搜题,也可以算是很经典的题了吧。

#include<bits/stdc++.h>
#define re register
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
	return x*f;
}
inline void print(int x){
	if(x/10) print(x/10);
	putchar(x%10+'0');
}
const int M = 2e5+10;
int n,k;
int vis[M],ans[M];
queue<int>q;
void bfs(){
	vis[n] = 1;
	ans[n] = 0;
	q.push(n);
	while(!q.empty()){
		int x = q.front();
		q.pop();
		if(x == k) return;
		if(x+1<=100000 && !vis[x+1]){
			q.push(x+1);
			vis[x+1] = 1;
			ans[x+1] = ans[x]+1;
		}
		if(x-1>=0 && !vis[x-1]){
			q.push(x-1);
			vis[x-1] = 1;	
			ans[x-1] = ans[x]+1;
		}
		if(x*2<=100000 && !vis[x*2]){
			q.push(x*2);
			vis[x*2] = 1;
			ans[x*2] = ans[x]+1;
		}
	}
}
signed main(){
	freopen("catchcow.in","r",stdin);
	freopen("catchcow.out","w",stdout);
	n=read(),k=read();
	if(k<n){
		printf("%d",n-k);
		return 0;
	}
	bfs();
	printf("%d",ans[k]);
	return 0;
}

T2 

 一道动态规划吧,方程也很好推。但要注意,数据范围可以两次DP,一次是不下降,一次是不上升,两次去一个最小值。

#include<bits/stdc++.h>
#define re register
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
	return x*f;
}
inline void print(int x){
	if(x/10) print(x/10);
	putchar(x%10+'0');
}
const int M = 2010;
const int inf = 1e9;
int f[M][M],a[M],b[M];
int ans;
int n;
void init(){
	memset(f,0,sizeof(f));
	for(re int i(1) ; i<=n ; ++i) f[i][0] = inf;
}
bool cmp(int x,int y) {return x > y;}
signed main(){
	freopen("grading.in","r",stdin);
	freopen("grading.out","w",stdout);
	n=read();
	for(re int i(1) ; i<=n ; ++i) a[i] = read(),b[i] = a[i];
	sort(b+1,b+n+1);
	init();
	for(re int i(1) ; i<=n ; ++i){
		for(re int j(1) ; j<=n ; ++j){
			f[i][j] = min(f[i][j-1],f[i-1][j]+abs(a[i]-b[j]));
		}
	}
	ans = f[n][n];
	init();
	sort(b+1,b+n+1,cmp);
	for(re int i(1) ; i<=n ; ++i){
		for(re int j(1) ; j<=n ; ++j){
			f[i][j] = min(f[i][j-1],f[i-1][j]+abs(a[i]-b[j]));
		}
	}
	printf("%d",min(ans,f[n][n]));
	return 0;
}

T3 

 暴力很好写吧,怎么说怎么写就行。线段是维护区间的最大值和最小值。考虑一个区间,如果最大值小于c,那么返回0,如果最小值大于c,返回这个区间的长度。其它的就是维护tag标记,每次下传就行,普通的线段树操作。

#include<bits/stdc++.h>
#define re register
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
	return x*f;
}
inline void print(int x){
	if(x/10) print(x/10);
	putchar(x%10+'0');
}
const int M = 4e6+1;
int a[M];
int n,q;
struct tree{
	int mi,mx,tag;
}t[M];
inline void update(int k){
	t[k].mx = max(t[k<<1].mx,t[k<<1|1].mx);
	t[k].mi = min(t[k<<1].mi,t[k<<1|1].mi);
}
inline void pushdown(int k){
	if(t[k].tag){
		t[k<<1].tag += t[k].tag;
		t[k<<1|1].tag += t[k].tag;
		t[k<<1].mx += t[k].tag;
		t[k<<1|1].mx += t[k].tag;
		t[k<<1].mi += t[k].tag;
		t[k<<1|1].mi += t[k].tag;
		t[k].tag = 0;
	}
}
inline void build(int k,int l,int r){
	if(l==r){t[k].mi=t[k].mx=a[l];return;}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	update(k);
}
inline void add(int k,int l,int r,int x,int y,int c){
	if(x<=l&&r<=y){
		t[k].mx+=c;
		t[k].mi+=c;
		t[k].tag+=c;
		return;
	}
	pushdown(k);
	int mid = (l+r)>>1;
	if(x<=mid) add(k<<1,l,mid,x,y,c);
	if(y>mid) add(k<<1|1,mid+1,r,x,y,c);
	update(k);
}
inline int query(int k,int l,int r,int x,int y,int c){
	if(x<=l&&r<=y&&c<=t[k].mi) return r-l+1;
	if(x<=l&&r<=y&&c>t[k].mx) return 0;
	pushdown(k);
	int mid = (l+r)>>1,ans=0;
	if(x<=mid) ans+=query(k<<1,l,mid,x,y,c);
	if(y>mid) ans+=query(k<<1|1,mid+1,r,x,y,c);
	update(k);
	return ans;
}
signed main(){
	freopen("magic.in","r",stdin);
	freopen("magic.out","w",stdout);
	n=read(),q=read();
	for(re int i(1) ; i<=n ; ++i) a[i] = read();
	build(1,1,n);
	for(re int i(1) ; i<=q ; ++i){
		char ch;
		int l,r,x;
		cin >> ch;
		l=read(),r=read(),x=read();
		if(ch == 'M') add(1,1,n,l,r,x);
		else printf("%d\n",query(1,1,n,l,r,x));
	}
	return 0;
}

 

举报

相关推荐

2022.3.14模拟赛总结

10.31日模拟赛总结

模拟赛

2022.4.3模拟赛

0218 模拟赛

0 条评论