Div. 2 ,C. Vasya and Robot

本文介绍了一种使用二分查找优化原本O(n^2)复杂度算法的方法,通过预处理和二分查找减少枚举长度的时间消耗,最终达到O(nlogn)的复杂度。文章详细解释了如何在O(n)复杂度内判断特定长度是否满足要求,以及如何通过撤销操作来计算最少操作数。

这个题目第一眼看并不是一个二分,仔细思考一下,要枚举长度,然后又要枚举起点,这里已经是O(n^2)的复杂度了,还要判断是否满足条件,如果预处理了,是能在O(1)的复杂度解决的。所以枚举长度这边可以用一个二分,这样复杂度就是O(nlogn)了,可以解决这个题目。

如何在O(n)的复杂度判断这个长度满不满足要求呢?

枚举起点就要O(n)了,接下来就是O(1)判断O不OK;预处理到第i个字母时往右往上偏移了几位,那么枚举到一段区间的时候,我们可以将那一段区间的操作全部撤销(反正全改,长度也是len),那么此时的位置移到目标点最少的操作num 就是现在的位置和终点在X轴上的偏移量+Y轴上的偏移量,如果len>num,那么len-num一定要是偶数,这样上下左右才可以抵消。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,ex,ey;
const int maxn=2e6+5;
struct X{
	ll r,u;
}f[maxn]; 
bool flag=0;
bool pd(int len){
	for(int i=1;i+len-1<=n;++i){
		ll rr=f[i+len-1].r-f[i-1].r,uu=f[i+len-1].u-f[i-1].u;//区间r和u的偏移量
		ll num=abs(ex-(f[n].r-rr))+abs(ey-(f[n].u-uu));//所需要的最小操作数
		if(len>=num&&(len-num)%2==0){
			flag=1;//说明可以走到终点
			return 1;
		}
	}
	return 0;
}
int main(){
	scanf("%lld",&n);
	getchar();
	f[0].r=0,f[0].u=0;
	char tmp;
	for(int i=1;i<=n;++i){
		scanf("%c",&tmp);//预处理
		if(tmp=='R')	f[i].r=f[i-1].r+1,f[i].u=f[i-1].u;
		if(tmp=='L')	f[i].r=f[i-1].r-1,f[i].u=f[i-1].u;
		if(tmp=='U')	f[i].u=f[i-1].u+1,f[i].r=f[i-1].r;
		if(tmp=='D')	f[i].u=f[i-1].u-1,f[i].r=f[i-1].r;
	}
	getchar();
	scanf("%lld%lld",&ex,&ey);
	if(f[n].r==ex&&f[n].u==ey)	cout<<0<<endl;
	else{
		int le=0,ri=n+1;
		while(ri>le){
			int mid=(le+ri)/2;
			if(pd(mid))	ri=mid;
			else	le=mid+1;
		}
		if(!flag)	cout<<-1<<endl;
		else	cout<<le<<endl;
	}
	return 0;
}

 

### Codeforces Round 260 Div. 1 题目及题解 #### A. Vasya and Multisets 在这道题目中,Vasya有一个由n个整数组成的序列。目标是通过将这些数分成若干组,使得每组中的所有数都相同,并且尽可能减少分组的数量。 为了实现这一目的,可以利用贪心算法来解决这个问题。具体来说,在遍历输入数据的同时维护当前最大频率计数器,对于每一个新遇到的不同数值增加一个新的集合[^1]。 ```cpp #include <bits/stdc++..h> using namespace std; void solve() { int n; cin >> n; unordered_map<int, int> freq; for (int i = 0; i < n; ++i) { int x; cin >> x; freq[x]++; } int maxFreq = 0; for (auto& p : freq) { maxFreq = max(maxFreq, p.second); } cout << maxFreq << "\n"; } ``` #### B. Pashmak and Graph 此问题涉及图论领域的一个经典最短路径计算案例。给定一张带权无向图以及起点S和终点T,要求求出从S到T经过至少一条边后的最小花费总和。 Dijkstra算法适用于此类场景下的单源最短路径查询任务。初始化距离表dist[]为无穷大(INF),仅设置起始节点的距离为零;随后借助优先队列选取未访问过的最近邻接顶点u更新其相邻结点v至目前为止所知的最佳到达成本min{dist[u]+w(u,v)}直至找到终止条件即抵达目的地t或处理完毕所有可达区域内的候选者为止。 ```cpp typedef pair<long long,int> pli; const long long INF = LLONG_MAX / 3; struct Edge { int to, cost; }; vector<Edge> G[MAX_V]; long long d[MAX_V]; bool dijkstra(int s, int t){ priority_queue<pli,vector<pl>,greater<pl>> que; fill(d,d+MAX_V,INF); d[s]=0; que.push(pli(0,s)); while(!que.empty()){ pli p=que.top();que.pop(); int v=p.second; if(d[v]<p.first) continue; for(auto e:G[v]){ if(d[e.to]>d[v]+e.cost){ d[e.to]=d[v]+e.cost; que.push(pli(d[e.to],e.to)); } } } return d[t]!=INF; } ``` #### C. DZY Loves Colors 这是一道关于颜色染色的问题。给出长度为N的一维网格,初始状态下每个格子都有一个默认的颜色编号。现在有M次操作机会改变某些位置上的色彩值,最终目的是统计整个条带上共有几种不同的色调存在。 采用离散化技术预处理原始输入并记录下各段连续同色区间的端点坐标范围,之后针对每一次修改请求动态调整受影响部分的信息结构体(如线段树),最后依据累积的结果得出答案。 ```cpp // 假设已经实现了上述提到的数据结构 SegmentTree 和 update 函数 SegmentTree st; for(int i=1;i<=m;++i){ int l,r,c; scanf("%d%d%d",&l,&r,&c); update(l,r,c); } printf("%lld\n",st.query()); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值