文章目录
A - Sign Flipping [思维]
题意
可以改变任意位置的数,使 a [ i ] = − a [ i ] a[i] = -a[i] a[i]=−a[i]
最终要令长度为 n n n 的数组 a [ ] a[] a[] 中,(保证 n n n 为奇数)
a [ i + 1 ] − a [ i ] > = 0 a[i+1]-a[i] >= 0 a[i+1]−a[i]>=0 的 i i i 的个数至少有 n − 1 2 \frac{n-1}{2} 2n−1 个
a [ i + 1 ] − a [ i ] < = 0 a[i+1]-a[i] <= 0 a[i+1]−a[i]<=0 的 i i i 的个数至少有 n − 1 2 \frac{n-1}{2} 2n−1 个
分析
只要按序输出整数负数交替就可以
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100 + 5;
int a[maxn];
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
if((i % 2 && a[i] < 0) || (i % 2 == 0 && a[i] > 0))
a[i] = -a[i];
}
for(int i = 1; i <= n; ++i)
printf("%d%c", a[i], i == n ? '\n' : ' ');
}
return 0;
}
B - Neighbor Grid [构造]
题意
一个 n × m n \times m n×m 的矩阵,若矩阵上为 k > 0 k > 0 k>0,则表示与它相邻的格子为非零数的个数有 k k k 个。
每个格子上的数可以 + 1 +1 +1 地增加。
构造一个满足给定要求的矩阵,如果不存在输出 − 1 -1 −1
分析
只要满足 k < = 4 − 边 界 的 个 数 k <= 4 - 边界的个数 k<=4−边界的个数 就是有解的情况
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 300 + 5;
int a[maxn][maxn];
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
scanf("%d", &a[i][j]);
bool f = true;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
int x = 4 - (i == 1 || i == n) - (j == 1 || j == m);
if(a[i][j] > x) {
f = false; break;
}
a[i][j] = x;
}
if(!f) break;
}
if(!f) puts("NO");
else{
puts("YES");
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
printf("%d%c", a[i][j], j == m ? '\n' : ' ');
}
}
return 0;
}
C - Element Extermination [思维] ★
题意
一段连续增长的子区间中可以缩短成其中一个元素的值
给一个 n n n 个数的数组 a [ i ] , a [ i ] ∈ [ 1 , n ] a[i], a[i] \in [1, n] a[i],a[i]∈[1,n],每个元素都不相同
问最后是否能缩减成数组只包含一个元素
分析
万万没想到,我写了半天的代码,竟然只要判断首尾 o(╥﹏╥)o
其实只需要满足 a [ 1 ] < a [ n ] a[1] < a[n] a[1]<a[n] 则一定可以缩减为只剩 1 个元素,可以通过找规律
比如说一个数组 [2 1 5 3 4]
由于 a [ 1 ] < a [ n ] a[1] < a[n] a[1]<a[n] 满足
若 a [ n ] < n a[n] < n a[n]<n,则 a [ i ] = n a[i] = n a[i]=n 必然存在于 1 < i < n 1 < i < n 1<i<n 中,则前部分 a [ 1 ] . . . a [ i ] a[1] ... a[i] a[1]...a[i]最后必然能缩减为 a [ 1 ] a[1] a[1]
类似这样推导
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
int a[maxn];
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
printf("%s\n", a[1] > a[n] ? "NO" : "YES");
}
return 0;
}
D - Replace by MEX [暴力]
题意
有 n n n 个数的数组 a [ i ] a[i] a[i],该数组的 M E X MEX MEX 定义为当前数组中未出现的最小元素(从 0 0 0 开始)
每次可以选择数组中的一个数,用当前数组的 M E X MEX MEX 替换掉
问最后要得到一个非单调递减序列,替换的位置顺序应是如何,输出任意解
分析
可以发现不管怎样替换,都可以最终替换成 [0, 1, 2, …, n-1] 这样的数组
也就是说最后的目标是构造成 a [ i ] = i − 1 a[i] = i - 1 a[i]=i−1 这样的数组
又 n < = 1000 n <= 1000 n<=1000, n 2 n^2 n2 暴力
每次找出当前数组的 M E X MEX MEX,如果 M E X > n − 1 MEX > n - 1 MEX>n−1 即 M E X = n MEX = n MEX=n,则随便找一个 a [ i ] ! = i − 1 a[i] != i - 1 a[i]!=i−1 的位置进行替换
否则只要替换成 a [ M E X ] = M E X a[MEX] = MEX a[MEX]=MEX
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 5;
int a[maxn];
int res[maxn];
int cnt[maxn];
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < n; ++i) {
scanf("%d", &a[i]); cnt[a[i]] += 1;
}
int k = 0;
while(true) {
int pos = 0;
// for(int i = 0; i < n; ++i)
// printf("%d%c", a[i], i + 1 == n ? '\n' : ' ');
while(pos < n - 1 && a[pos] <= a[pos + 1]) pos += 1;
if(pos + 1 == n) break;
pos = 0;
while(cnt[pos]) pos += 1; // mex
if(pos >= n) {
for(int i = 0; i < n; ++i) {
if(a[i] != i) {
cnt[a[i]] -= 1, cnt[pos] += 1;
a[i] = pos, res[k++] = i;
break;
}
}
}else{
cnt[a[pos]] -= 1, cnt[pos] += 1;
a[pos] = pos, res[k++] = pos;
}
}
printf("%d\n", k);
if(k == 0) puts("");
for(int i = 0; i < k; ++i)
printf("%d%c", res[i] + 1, i + 1 == k ? '\n' : ' ');
}
return 0;
}
E - Inversion SwapSort [逆序对][构造] ★★★
目录
题目传送门
参考博客 Codeforces 1375 E. Inversion SwapSort —— 想法,贪心
题意
给定一个数组 a [ ] a[] a[],有 n n n 个数
若满足 u < v & & a [ u ] > a [ v ] u < v \& \& a[u] > a[v] u<v&&a[u]>a[v],则两个数可以交换位置(即为逆序对的时候)
问要交换哪几对 ( u , v ) (u, v) (u,v) 后,可以得到不递减序列(这一场好经常出现这个)
分析
需要先对数组排序,按照 a [ i ] a[i] a[i] 升序,然后 i i i 升序这样排序
每次取逆序对的时候就从 a [ i ] a[i] a[i] 小的开始取
找逆序对的时候就找 a [ j ] < a [ i ] & & j > i a[j] < a[i] \&\& j > i a[j]<a[i]&&j>i 的,然后放到数组中
对于一开始找 a [ i ] a[i] a[i] 比较小的处理后,可以将后面的数序列中除了比 a [ i ] a[i] a[i]大的,是不递减的序列
因此处理 a [ i + 1 ] > a [ i ] a[i + 1] > a[i] a[i+1]>a[i] 的时候,也可以保证从后往前依次一个一个交换的时候,可以满足 a [ i ] > a [ j ] a[i] > a[j] a[i]>a[j] 的条件
最终可以再保持后面的数序列中除了比 a [ i + 1 ] a[i + 1] a[i+1]大的,是不递减的序列
举个栗子
[4 2 3 1]
数组 ( a [ i ] , i ) (a[i], i) (a[i],i) 排序后得到
( 1 , 4 ) ; ( 2 , 2 ) ; ( 3 , 3 ) , ( 4 , 1 ) (1, 4); (2, 2); (3, 3), (4, 1) (1,4);(2,2);(3,3),(4,1)
i = 1 (1, 4): 无; → \rightarrow → [4 2 3 1]
i = 2 (2, 2): j = 4 j = 4 j=4; → \rightarrow → [4 1 3 2]
i = 3 (3, 3); j = 4 j = 4 j=4; → \rightarrow → [4 1 2 3]
i = 4 (4, 1); j = 4 , 3 , 2 j = 4, 3, 2 j=4,3,2;
→ \rightarrow → [3 1 2 4] → \rightarrow → [2 1 3 4] → \rightarrow → [1 2 3 4]
Code
#include <bits/stdc++.h>
#define pii pair<int, int>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 5;
int a[maxn];
vector<pii> v, v2;
int main() {
int n;
scanf("%d", &n);
v.clear(), v2.clear();
for(int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
v.push_back(make_pair(a[i], i));
}
sort(v.begin(), v.end());
for(int i = 0; i < n; ++i) {
int x = v[i].se;
for(int j = n - 1; j > x; --j) {
if(a[x] > a[j])
v2.push_back(make_pair(x, j));
}
}
printf("%d\n", (int)v2.size());
for(auto i : v2)
printf("%d %d\n", i.fi + 1, i.se + 1);
return 0;
}