【ABC393】题目记录

[ABC393A] Poisonous Oyster

简单题。根据情况判断即可。

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string s1,s2;
int main(){
	cin>>s1>>s2;
	if(s1[0]=='s'&&s2[0]=='s') cout<<1<<endl;
	if(s1[0]=='s'&&s2[0]=='f') cout<<2<<endl;
	if(s1[0]=='f'&&s2[0]=='s') cout<<3<<endl;
	if(s1[0]=='f'&&s2[0]=='f') cout<<4<<endl;
	return 0;
}

[ABC393B] A..B..C

字符串长度并不长,考虑枚举第一个字符位置和间距,计算出三个字母的位置,判断这三个位置的字母是否符合要求即可。

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string s;
ll l,ans;
int main(){
	cin>>s;
	l=s.length();
	for(int i=0;i<l;i++)
		for(int j=1;i+j+j<l;j++)
			if(s[i]=='A'&&s[i+j]=='B'&&s[i+j+j]=='C')
				ans++;
	cout<<ans<<endl;
	return 0;
}

[ABC393C] Make it Simple

需要做的事情是给一个无向图,让它不重边。

那只需要排除自环,排除重边就可以了。

我们可以统计不重复的边的数量。为了防止出现类似于 \((u,v)\)\((v,u)\) 的重边,可以在前一个结点编号大于后一个结点编号的时候互换两个结点的编号,这样就可以避免这种情况了。然后将这些边当中不自环的边都扔到 set 里面得到去重后边的数目,然后总的边数减去去重后边的数目就是答案。

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,u,v;
set< pair<ll,ll> > edges;
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>u>>v;
		if(u==v) continue;
		else if(u>v) swap(u,v);
		edges.insert({u,v});
	}
	cout<<m-edges.size()<<endl;
	return 0;
}

[ABC393D] Swap to Gather

一道标准的绝对值不等式题目,找到最中间的 \(1\),然后手动计算换过去需要的距离就可以了。

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll N,ans;
vector<ll> pos;
int main(){
	cin>>N;
	for(int i=1;i<=N;i++){
		char a;
		cin>>a;
		if(a=='1') pos.push_back(i);
	}
	ll ct=pos.size()/2,l=pos.size();
	for(int i=0;i<ct;i++)
		ans+=(pos[ct]-pos[i]-ct+i);
	for(int i=ct+1;i<l;i++)
		ans+=(pos[i]-pos[ct]+ct-i);
	cout<<ans<<endl;
	return 0;
}

[ABC393E] GCD of Subset

一开始的时候,我看到这个题目,想到的是暴力枚举组合(但是显然不能做到)。

\(A_i\) 的值域是 \(10^6\),这个范围下,我们考虑统计每个数出现的次数,然后枚举每个约数,对于每个约数,通过枚举这个约数的倍数的方式,统计数组中能被这个数整除的数的个数。然后我们枚举约数,如果数组中有超过 \(K\) 个数能被这个约数整除,我们就可以通过枚举这个约数的倍数的方式,更新该数字的答案值。

最后从前往后,通过数组中的值调用前面预处理的答案数组,输出答案即可。

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k,a[1200010],frq[1000010],d[1000010],ans[1000010];
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		frq[a[i]]++;
	}
	for(int i=1;i<=1000000;i++)
		for(int j=i;j<=1000000;j+=i)
			d[i]+=frq[j];
	for(ll i=1000000;i>=0;i--){
		if(d[i]<k) continue;
		for(int j=i;j<=1000000;j+=i)
			ans[j]=max(ans[j],i);
	}
	for(int i=1;i<=n;i++)
		cout<<ans[a[i]]<<endl;
	return 0;
}

[ABC399F] Prefix LIS Query

你说的对,但是《线段树优化DP》是由Tarjan实验室自主研发的一款全新动态规划优化算法。算法发生在一个被称作「状态转移域」的抽象数学空间,在这里,被红名大佬选中的人将被授予「区间查询之力」,导引时间复杂度优化。你将扮演一位名为「ACMer」的神秘选手,在充满bug的代码中邂逅性质各异、复杂度独特的优化技巧,和它们一起击败TLE的压迫,找回被卡常掩盖的AC——同时,逐步掌握「线段树优化DP」的精髓。

总之这个题目我们可以用线段树解决。(DP?那是什么?)值域很大达到了 \(10^9\),所以需要离散化处理。

首先按照贪心结合二分的方法求出每个位置的最长上升子序列,用数组存储每个位置的最长上升子序列。

接下来处理询问:由于不需要强制在线,我们把所有的询问按 \(R\) 值排序然后离线处理。对于前 \(R_i\) 个值,用单点赋值结合区间最大值线段树来维护最大值不大于某个值的最长上升子序列,添加一个新的数值的时候,只需要把该数值位置的线段树值单点修改为原值和这个值的最长上升子序列的长度的最大值就可以了。对于一个 \(X_i\) 最大值就是数值不超过 \(X_i\) 的位置中最长的最长上升子序列的长度,调用对应的线段树值即可。

复杂度是 \(O(N \log N+Q\log N)\),足以通过本题。

Code

// LUOGU_RID: 204043244
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,Q,a[200010],x[200010],res[200010],vallen;
ll cache[200010],tot;
struct Node{
	ll l,r,val;
} T[800010];
void build(ll l,ll r,ll id){
	T[id].l=l;T[id].r=r;
	if(l==r) return;
	else{
		ll mid=(r+l)/2;
		build(l,mid,id*2);
		build(mid+1,r,id*2+1);
	}
}
void modify(ll k,ll p,ll id){
	if(T[id].l==T[id].r){
		T[id].val=max(T[id].val,k);
	}else{
		ll mid=(T[id].l+T[id].r)/2;
		if(p<=mid) modify(k,p,id*2);
		if(mid<p) modify(k,p,id*2+1);
		T[id].val=max(T[id*2].val,T[id*2+1].val);
	}
}
ll check(ll l,ll r,ll id){
	if(l<=T[id].l&&T[id].r<=r) return T[id].val;
	else{
		ll mid=(T[id].r+T[id].l)/2,ans=0;
		if(l<=mid) ans=max(ans,check(l,r,id*2));
		if(mid<r) ans=max(ans,check(l,r,id*2+1));
		return ans;
	}
}

struct question{
	ll r,x,id,ans;
} q[200010];

bool comp1(question A,question B){
	return A.r<B.r;
}

bool comp2(question A,question B){
	return A.id<B.id;
}

ll findpos(ll val){
	ll l=1,r=vallen; 
	while(l<r){
		ll mid=(l+r+1)/2;
		if(x[mid]>val)  r=mid-1;
		else l=mid;
	}
	return l;
}

int main(){
	cin>>n>>Q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		x[i]=a[i];
		if(tot==0||a[i]>cache[tot-1]){
			cache[tot]=a[i];
			res[i]=++tot;
		}else{
			ll l=0,r=tot-1; 
			while(l<r){
				ll mid=(l+r)/2;
				if(cache[mid]>=a[i])  r=mid;
				else l=mid+1;
			}
			if(cache[l]>a[i]) cache[l]=a[i];
			res[i]=l+1;
		}
	}
	sort(x+1,x+n+1);
	vallen=unique(x+1,x+n+1)-x-1;
	build(1,vallen,1);
	for(int i=1;i<=Q;i++){
		cin>>q[i].r>>q[i].x;
		q[i].id=i;
	}
	ll pos=1;
	sort(q+1,q+Q+1,comp1);
	for(int i=1;i<=n;i++){
		modify(res[i],findpos(a[i]),1);
		while(q[pos].r<=i&&pos<=Q){
			q[pos].ans=check(1,findpos(q[pos].x),1);
			pos++;
		}
	}
	sort(q+1,q+Q+1,comp2);
	for(int i=1;i<=Q;i++) cout<<q[i].ans<<endl;
	
	return 0;
}
posted @ 2025-02-16 14:33  羽绘  阅读(86)  评论(0)    收藏  举报