「杂题乱刷2」CF109D
题目链接
CF109D Lucky Sorting 2000 (1800)
解题思路
我们考虑现将原序列离散化成排列,此时约束条件严格强于原题目,然后只找一个可以交换的数字,此时约束条件依然强于原题目。
那么此时我们考虑如何操作,设可以操作的数字为 \(id\):
-
如果此时数字 \(i\) 所在的位置为 \(i\),那么此时不需要交换。
-
如果此时数字 \(i\) 所在的位置不为 \(i\),且数字 \(id\) 所在的位置为 \(i\),那么此时交换 \(i,id\) 两个数字的位置。
-
如果此时数字 \(i\) 所在的位置不为 \(i\),且数字 \(id\) 所在的位置不为 \(i\),设位置 \(i\) 此时的数字为 \(id2\),那么此时先交换 \(id,id2\) 两个数字的位置。那么此时交换 \(id,i\) 两个数字的位置。
操作次数严格不大于 \(2n\)。
参考代码
ll n,id;
ll a[1000010];
ll b[1000010];
map<ll,ll>mp,mp2;
ll pos[1000010];
bool f(ll x)
{
ll pd=1;
while(x)
pd&=x%10==4 || x%10==7,
x/=10;
return pd;
}
vector<pii>ans;
void swp(ll x,ll y)
{
if(x==y)
return ;
swap(a[x],a[y]);
swap(pos[a[x]],pos[a[y]]);
ans.pb({x,y});
}
void _clear(){}
void solve()
{
_clear();
cin>>n;
forl(i,1,n)
cin>>a[i],
f(a[i])?id=i:id=id;
forr(i,n,1)
b[i]=a[i];
sort(b+1,b+1+n);
ll pd=1;
forl(i,1,n)
pd&=a[i]==b[i];
if(pd)
{
cout<<0<<endl;
return ;
}
ll k=1;
forl(i,1,n)
mp[a[i]]++;
for(auto i:mp)
mp2[i.x]=k,
k+=i.y;
forl(i,1,n)
a[i]=mp2[a[i]]++;
if(id==0)
{
cout<<-1<<endl;
return ;
}
// forl(i,1,n)
// cout<<a[i]<<' ';
// cout<<endl;
forl(i,1,n)
pos[a[i]]=i;
id=a[id];
forl(i,1,n)
{
if(pos[i]==i)
continue;
if(pos[id]==i)
swp(i,pos[i]);
else
swp(pos[id],i),
swp(i,pos[i]);
}
cout<<ans.size()<<endl;
for(auto i:ans)
cout<<i.x<<' '<<i.y<<endl;
}

浙公网安备 33010602011771号