AT_abc408

前言

这把手速失败了,共吃 4 发罚时,成为战犯。

A.Timeout

translation:

判断是否有 \(\forall 1\le i \le n,a_i-a_{i-1}\le S\),其中 \(a_0=0\)

扫一遍即可。
这个屑翻译了 2min 题意,被嘲讽了(

#include<bits/stdc++.h>
using namespace std; 
int S,T,a,b;
signed main(){
	cin>>T>>S;
	for(int i=1;i<=T;i++){
		cin>>b;
		if(b-a>S){
			cout<<"No"<<endl;
			return 0;
		}
		a=b;
	}
	cout<<"Yes"<<endl;
	return 0;
}

B.Compression

translation:

\(A\) 排序并去重后输出。

食用 STL 库即可。STL 真是美味啊!

#include<bits/stdc++.h>
using namespace std; 
int n,a[200005]; 
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+n+1);
	n=unique(a+1,a+n+1)-a;
	cout<<n-1<<endl;
	for(int i=1;i<n;i++)cout<<a[i]<<" "; 
	return 0;
}

C.Not All Covered

translation:

给定若干个区间,求要存在一个点使得其不被任何区间覆盖,至少要删掉多少区间。

转换一下,题目问的就是做若干次区间 \(+1\) 然后查询全局最小值。
差分一下即可。

此人数组开小白吃一发罚时 😦

#include<bits/stdc++.h>
using namespace std; 
int n,m,a[1000005]; 
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int l,r;cin>>l>>r;
		a[l]++;a[r+1]--;
	}
	int mn=0x3f3f3f3f,A=0;
	for(int i=1;i<=n;i++)A+=a[i],mn=min(mn,A);
	cout<<mn<<endl;
	return 0;
}

D.Flip to Gather

translation:

给定一个 \(01\) 串,将一个 \(0\) 变成 \(1\) 或将一个 \(1\) 变成 \(0\) 视为一次操作。求最少的操作数使得串内至多有一段连续的 \(1\)

枚举连续 \(1\) 的结束点,计算后缀中 \(1\) 的个数。然后设 \(pre_{i,0/1}\) 为以 \(i\) 结尾且合法,最后一个字符为 \(0/1\) 的最小操作次数。那么有:
\(pre_{i,0}=pre_{i-1,0}+[s_i=1]\)
\(pre_{i,1}=\min(pre_{i-1,0},pre_{i-1,1})+[s_i=0]\)

最终答案为 \(\min_{1\le i\le n}pre_{i-1,1}+suf_i\)

#include<bits/stdc++.h>
using namespace std; 
int n;
char s[200005];
int pre[200005][2],suf[200005];
signed main(){
	int T;cin>>T;
	while(T--){
		cin>>n;
		scanf("%s",s+1);
		pre[0][0]=pre[0][1]=0;
		for(int i=1;i<=n;i++){
			if(s[i]=='1'){
				pre[i][0]=pre[i-1][0]+1;
				pre[i][1]=min(pre[i-1][1],pre[i-1][0]);
			}
			else{
				pre[i][0]=pre[i-1][0];
				pre[i][1]=min(pre[i-1][1],pre[i-1][0])+1;
			}
		}
		suf[n+1][0]=suf[n+1][1]=0;
		int ans=min(pre[n][0],pre[n][1]); 
		for(int i=n;i>=1;i--){
			suf[i]=suf[i+1]+(s[i]=='1');
			ans=min(ans,suf[i]+pre[i-1][1]);
		}
		cout<<ans<<endl; 
	}
	return 0;
}

E.Minimum OR Path

translation:

最短路,路径权值为路径上所有边边权按位或的结果。

从高位到低位判断最终结果能否在该位以下即可。

具体的,利用并查集求最小生成树,每次取出最大边边权的最高位 \(2^k\),去除所有边权 \(\ge 2^{k+1}\) 的边,剩下的所有边去掉 \(2^k\) 这一位,然后重复,直到没有剩下的边或者剩下的边权都为 \(0\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
struct edge{
	int x,y,w;
	bool operator < (const edge & B) const {
		return w<B.w;
	}
}e[200005];
int n,m;
int fa[200005];
int find(int x){
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
} 
signed main(){
	cin>>n>>m;
	for(int i=0;i<m;i++){
		cin>>e[i].x>>e[i].y>>e[i].w;
	}
	sort(e,e+m);
	int ans=0;
	for(int k=29;k>=0;k--){
		for(int i=1;i<=n;i++)fa[i]=i;
		int mx=0;
		for(int i=0;i<m;i++){
			int fx=find(e[i].x),fy=find(e[i].y);
			mx=e[i].w;
			if(fx==fy)continue;
			fa[fx]=fy;
			if(find(1)==find(n))break;
		}
		int S=log2(mx);
		if(m==0||mx==0)break;
		ans|=(1<<S);
		m=lower_bound(e,e+m,edge{0,0,1<<(S+1)})-e;
		for(int i=0;i<m;i++)if(e[i].w&(1<<S))e[i].w-=(1<<S);
		sort(e,e+m);
	}
	cout<<ans<<endl;
	return 0;
}

F.Athletic

translation:

给定一个排列 \(p\),规定位置 \(i\) 可以移动到任意满足 \(|i-j|\le R,p_j\le p_i+D\) 的位置 \(j\)。问从某个位置开始,至多能做多少次移动。

一个 dp。朴素的想法是按照 \(p_i\) 从大到小更新,每次取 \(dp_i=1+\max_{|i-j|\le R,p_j\le p_i+D}dp_j\),但是我们发现这是平方量级的。

考虑如何优化。我们发现这个更新过程本质上是一个区间最大值,于是考虑线段树。初始时每个位置都是 \(-1\),当我们更新到 \(p_i\) 时,将 \(p_{i}+D\)(如果存在)的值更新到线段树内,然后查询区间最大值并记录即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,mx[2000005];
void pushup(int x){
    mx[x]=max(mx[x<<1],mx[x<<1|1]);
}
void build(int x,int l,int r){
	if(l>r)return;
    if(l==r){
		mx[x]=-1;
		return;
	}
	int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}
void upd(int x,int l,int r,int ps,int k){
	if(l==r){
		mx[x]=k;
		return;
	}
	int mid=(l+r)>>1;
	if(ps<=mid)upd(x<<1,l,mid,ps,k);
    else upd(x<<1|1,mid+1,r,ps,k);
    pushup(x);
}
int query(int x,int l,int r,int L,int R){
    if(L<=l&&r<=R)return mx[x];
	int mid=(l+r)>>1,res=-1;
    if(L<=mid)res=max(res,query(x<<1,l,mid,L,R));
    if(R>mid) res=max(res,query(x<<1|1,mid+1,r,L,R));
    return res;
}
int p[500005],ip[500005],R,D,ans[500005];
signed main(){
    cin>>n>>D>>R;
    for(int i=1;i<=n;i++)cin>>p[i],ip[p[i]]=i;
    build(1,1,n);
    for(int i=n;i>=1;i--){
    	if(i+D<=n)upd(1,1,n,ip[i+D],ans[i+D]);
    	int l=max(1ll,ip[i]-R);
    	int r=min(n,ip[i]+R);
    	ans[i]=query(1,1,n,l,r)+1;
	}
	int res=0;
	for(int i=1;i<=n;i++)res=max(res,ans[i]);
	cout<<res<<endl;
    return 0;
}

G.A/B < p/q < C/D

translation:

给定 \(A,B,C,D\),求最小的 \(q\) 使得存在 \(p\) 满足 \(\frac{A}{B}<\frac{p}{q}<\frac{C}{D}\)

看到标题这怎么是典题?翻译一下还真是典中典啊!
P5179 Fraction 启动!

#include <bits/stdc++.h>
using namespace std;
#define int long long
void gcd(int a,int b,int&p,int&q,int c,int d) {
	if(a<b&&c>d)p=q=1;
	else {
		gcd(d%c,c,q,p,b-(d/c)*a,a);
		q+=(d/c)*p;
	}
}
int a,b,c,d;
signed main(){
	int T;cin>>T;
	while(T--){
		cin>>a>>b>>c>>d;
		int p,q;gcd(a,b,p,q,c,d);
		cout<<q<<'\n';
	}
	return 0;
}
posted @ 2025-05-31 22:09  Xuan_qwq  阅读(132)  评论(2)    收藏  举报