昨天晚上巨困,就没有打,今天课间的时候就看了一下D题,发现好像可以瞎搞,于是吃完饭就写了一下,调过样例一次就A了qaq。
D. Sequence and Swaps
枚举+贪心
由于数据范围 n ≤ 500 n\leq500 n≤500,由此我们可以在 n 3 n^3 n3完成此题。
最后完成所有操作后,我们手中肯定还有一个数,我们考虑去枚举这个数。
最后手里的数一定不在最终的排列中,于是用一个数组b[]
把除了手中的数记录下来,不难发现只要排序一下这个所有数的位置就确定了。
而且不难发现如果当前手中的数是 x x x,我们必须一次将他归位,于是就模拟操作,每次找出现在手中的数在b[]
数组中的位置(注意重复的数只需要开一个st[]
数组记录一下即可),然后看看能不能执行交换操作,把过程模拟一边,顺便记录次数。
模拟过程中,如果当前手中的数已经是枚举剩余的数之间跳出循环,如果不能交换说明不合法也直接跳出循环。
最后再判断一下是否满足条件即可。
时间复杂度 O ( n 3 ) O(n^3) O(n3)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=510;
int a[N],b[N],c[N];
bool st[N];
int main()
{
IO;
int T=1;
cin>>T;
while(T--)
{
int n,x;
cin>>n>>x;
for(int i=1;i<=n;i++) cin>>a[i];
bool fl=1;
for(int i=2;i<=n;i++)//特判最后手中的数是 x 也就是不用操作
if(a[i]<a[i-1]) fl=0;
if(fl)
{
cout<<0<<'\n';
continue;
}
a[n+1]=x;
int res=0x3f3f3f3f;
for(int i=1;i<=n;i++)// 枚举剩下的数是a[i]
{
for(int j=1;j<=n;j++)
{
if(i==j)
b[j]=x;
else
b[j]=a[j];
}
sort(b+1,b+1+n);
int tmp=x;
memcpy(c,a,sizeof c);
bool ok=1;
int cnt=0;
for(int j=1;j<=n;j++)
{
memset(st,0,sizeof st);
int k;
for(k=1;k<=n;k++)// 找到当前手中的数应该所在的位置
{
if(b[k]==tmp&&c[k]!=tmp)
{
while(st[k]||c[k]==tmp) k++;
st[k]=1;
break;
}
}
if(c[k]>tmp) // 能不能执行交换操作
{
swap(c[k],tmp);
cnt++;
if(tmp==a[i]) break;//手中的数已经是枚举的数
}
else// 交换失败
{
ok=0;
break;
}
}
for(int i=2;i<=n;i++)
if(c[i]<c[i-1]) ok=0;
if(a[i]!=tmp) ok=0;// 最后手中的数tmp一定要等于枚举的数a[i]
if(ok) res=min(res,cnt);
}
if(res==0x3f3f3f3f) cout<<-1<<'\n';
else cout<<res<<'\n';
}
return 0;
}
感觉应该有复杂度更优的做法,但是我这个做法若优化感觉十分难写~~
要加油哦~