题目大意:
给定一个长度为n的序列和一个正整数k。
在一次操作中,可以对i i i 和j ( 1 ≤ i < j ≤ n ) j(1 \le i\lt j \le n) j ( 1 ≤ i < j ≤ n ) 交换p i p_i p i 和p j p_j p j 。
为了使p 1 + p 2 + . . . + p k p_1 + p_2 + ...+p_k p 1 + p 2 + . . . + p k 的总和尽可能的小,最少需要多少次操作?
思路:
对于一个序列的前k k k 项,一定是1 + 2 + . . . + k 1+2+...+k 1 + 2 + . . . + k 的总和是最小的。
所以我们只要统计给定的序列p p p 的前k k k 项中有几个是大于k k k 的即可,对于这些不在1~k k k 范围内的元素要进行交换。
AC Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void solve() { int n,k; cin >> n >> k; vector<int> a(n + 1); map<int,int> mp; for (int i = 1;i <= n;i ++) { cin >> a[i]; if (i <= k) mp[a[i]] = 1; } int ans = 0; for (int i = 1;i <= k;i ++) if (mp[i] == 0) ans ++; cout << ans << endl; }
题目大意:
给定一个正整数n,要求构造一个permutation使得每一个i i i 和p i p_i p i 的最小公倍数之和最大。
思路:
由于相邻的两个数一定互质,而互质数的最小公倍数最大,所以当只要输出两个相邻的数即可。
当n为奇数时,先输出一个1,然后从i从2开始输出i+1和i
当n为偶数时,i从1开始输出i+1和i
AC Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void solve() { int n; cin >> n; if (n & 1) { cout << 1 << ' '; for (int i = 2;i <= n;i += 2) cout << i + 1 << ' ' << i << ' '; } else for (int i = 1;i <= n;i += 2) cout << i + 1 << ' ' << i << ' '; puts(""); }
题目大意:
给定一个长度为n的正整数数组。
在一次操作内:
1.选择一个整数数x x x
2.对于数组中所有值等于x x x 的元素,全部将其改变成0
求最少多少次操作可以使得这个数组成为非递减排序
思路:
要想成为非递减排序,任意一个0的前面都应该是0,也就是说如果数组中间出现一个0,那么这个0的前面都应该是0才符合要求。
所以我们要找到的就是最后一个0出现的位置,也就是最后一个a[i] > a[i + 1]的位置i d x idx i d x 。
然后统计i d x idx i d x 前的有多少个不同的数字,在找到i d x idx i d x 后最后一个被统计过的元素,枚举i d x idx i d x 到最后一个被统计过的元素之间有几个未被统计过的元素。
AC Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 void solve() { int ans = 0; int n; cin >> n; vector<int> cnt; vector<int> a(n + 1); map<int,int> mp; for (int i = 1;i <= n;i ++) cin >> a[i]; int idx = n; for (int i = n;i > 1;i --) if (a[i] < a[i - 1]) break; else idx = i - 1; for (int i = 1;i < idx;i ++) if (mp[a[i]] == 0) { ans ++; mp[a[i]] = 1; } for (int i = n;i >= idx;i --) { if (mp[a[i]]) { for (int j = i;j >= idx;j --) if (mp[a[j]] == 0) { ans ++; mp[a[j]] = 1; } break; } } cout << ans << endl; }