【牛客 - 551E】CSL 的魔法(贪心,思维,STLmap,分块)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/88951050

题干:

链接:https://ac.nowcoder.com/acm/contest/551/E
来源:牛客网

有两个长度为 n 的序列,a0,a1,…,an−1a0,a1,…,an−1和 b0,b1,…,bn−1b0,b1,…,bn−1。CSL 有一种魔法,每执行一次魔法,可以任意挑选一个序列并任意交换序列中两个元素的位置。CSL 使用若干次魔法,得到最终的序列 a 和 b,并且想要让 a0b0+a1b1+…+an−1bn−1a0b0+a1b1+…+an−1bn−1的值最小化。求解 CSL 至少使用多少次魔法,能够达到最小化的目标。

输入描述:

第一行有一个整数 n,表示序列的长度。

接下来两行,每行有 n 个整数,分别表示初始序列 a 和 b。

输入数据保证每个序列里的数两两不同。

2≤n≤1052≤n≤105
1≤ai,bi≤1091≤ai,bi≤109

输出描述:

在一行输出一个整数,表示最少使用的魔法次数。

示例1

输入

复制

2
1 2
1 2

输出

复制

1

示例2

输入

复制

2
1 2
2 1

输出

复制

0

解题报告:

  首先通过贪心不难证明,当两个数组分别是最大值和最小值匹配的时候,这样刚好达到最小值。所以就是怎么通过最小步数让a数组可以从大到小排列就可以了。

  那么后面这一步的实现方法就很多了。该AC代码只是提供了一种方式。还可以用离散数学中置换群的概念来理解(如果没记错应该是叫这个),大概一堆概念什么对换变换置换一类操作,,具体忘记了,总之就是可以得出一堆环来,每个环之间的数一次替换就可以排列好,也就是分成若干个块,块间不影响。。(因为你换一次操作至少能对齐一个吧,就是你换走的这个。当然如果巧合,换过来的这个刚好就是你需要的,那就完美了,对于这个块的操作就结束了)。对于上述步骤,可以利用该思想暴力,也可以直接算出这个块中有多少数字,假设涉及x个数字,然后直接(x-1)就是答案。。又因为总块数是n,那么换句话说,只需要数出有多少个块cnt,然后n-cnt就是答案。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e5 + 5;
int a[MAX],b[MAX],aa[MAX],bb[MAX];
map<int,int> mp,mb;//mb存b数组每个数字的位置。  mp存本应该在的位置 
int main()
{
	int n;
	cin>>n;
	for(int i = 1; i<=n; i++) cin>>a[i],aa[i] = a[i];
	for(int i = 1; i<=n; i++) cin>>b[i],mb[b[i]] = i;
	sort(aa+1,aa+n+1);sort(b+1,b+n+1,greater<int>());
	for(int i = 1; i<=n; i++) mp[aa[i]] = mb[b[i]];
	int ans = 0;
	for(int i = 1; i<=n; i++) {
		while(mp[a[i]]!=i) swap(a[i],a[mp[a[i]]]),ans++;
	}
	printf("%d\n",ans);
	return 0 ;
}

AC代码2:(分块的方法,省掉了map,跑的飞快) 

#include <bits/stdc++.h>
using namespace std;
 
typedef pair<int, int> pii;
#define ff first
#define ss second
#define mp make_pair
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<pii> ab(n);
    vector<int> next(n);
    vector<bool> vis(n, false);
    for (int i = 0; i != n; ++i) cin >> ab[i].ff;
    for (int i = 0; i != n; ++i) cin >> ab[i].ss;
    sort(ab.begin(), ab.end());
    for (int i = 0; i != n; ++i) ab[i].ff = i;//映射到新值1~n内
    sort(ab.begin(), ab.end(), [] (const pii& x, const pii& y) { return x.ss > y.ss; });
    for (int i = 0; i != n; ++i) next[i] = ab[i].ff;
    int res = 0;
    for (int i = 0; i != n; ++i) if (!vis[i]) {
        ++res;
        while (!vis[i]) {
            vis[i] = true;
            i = next[i];
        }
    }
    cout << n - res << endl;
}

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/88951050