*题解:CF2266D Falling Concrete

题目链接

解析

首先可以发现,通过相邻两个数的操作的组合,可以实现任意操作。

对于操作 \((i,i + 1)\),其效果为 \(a_i' \leftarrow a_{i + 1} - 1,a_{i + 1}'\leftarrow a_{i} + 1\),这是以下标为参考系得到的。倘若以 \((i,a_i)\) 这个元素为参考系,注意这里所指的元素包含下标属性,那么效果就为 \((i,a_i) \leftarrow (i + 1,a_i + 1)\)。以 \(a_{i + 1}\) 为参考系同理。

观察发现对于元素 \((i,a_i)\)\(a_i - i\) 始终不变,记 \(b_i = a_i - i\),则 \(a\) 中的相等连续段在 \(b\) 上体现为 \(b_i = b_{i - 1} - 1\),操作在 \(b\) 上体现为取出一个元素并重新选取位置插入。

不难发现通过操作可以到达 \(b\) 的任意排列。

故排序去重后扫一遍统计最长公差为 \(-1\) 的等差数列长度即可,时间复杂度 \(O(n\log n)\)

想到了的地方

将操作分解。

没想到的地方

\(a_i - i\) 不变。

没想到的原因

对于元素位置变换,值变换的问题,未能以元素下标二元组的角度来思考。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 3000 + 5,M = 15,K = 10000 + 5,mod = (int)1e9 + 7;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);	
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;
	cin>>T;
	while(T--){
		int n;
		cin>>n;
		vector<int> v;
		for(int i=1;i<=n;i++){
			int x;
			cin>>x;
			v.push_back(x - i);
		}
		sort(v.begin(),v.end(),greater<int>());
		v.erase(unique(v.begin(),v.end()),v.end());
		int cnt = 1,res = 0;
		for(int i=1;i<v.size();i++){
			if(v[i] == v[i - 1] - 1){
				cnt++;
			}else{
				res = max(res,cnt);
				cnt = 1;
			}
		}
		res = max(res,cnt);
		cout<<res<<'\n';
	}
	return 0;
}
posted @ 2026-09-22 09:04  yutar  阅读(6)  评论(0)    收藏  举报