*题解: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;
}

浙公网安备 33010602011771号