「杂题乱刷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号