A.Sign Flipping
题意:给一个包含
n
n
n个整数的数组,可以随意改变他们的正负号使得至少有
n
−
1
2
\frac{n-1}{2}
2n−1个相邻数字的差
≥
0
\ge0
≥0,且至少有
n
−
1
2
\frac{n-1}{2}
2n−1个相邻数字的差
≤
0
\leq0
≤0。
对于任意的三个数字
a
a
a,
−
b
-b
−b,
c
c
c,其中
a
a
a,
b
b
b,
c
c
c >
0
0
0,一定符合以上我们所说的要求。我们再延申至任意长度的数组。
int n, k;
int a[105];
void solve()
{
cin >> n;
bool f = 1;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
a[i] = abs(a[i]);
}
for (int i = 1; i <= n; i++)
{
if (f)cout << a[i] << " ";
else cout << -a[i] << " ";
f ^= 1;
}
cout << endl;
}
B.Neighbor Grid
题意:给一个
n
×
m
n×m
n×m的矩阵,由非负整数填充。我们定义一个good矩阵:对于每一个格子,他的数字一定等于他的所有相邻格子当中格子的数字大于
0
0
0的数量。我们可以给任意一个格子的数字+1,并且可以执行任意次。问最初给的矩阵能否变成good矩阵。
首先看到这是B题,我们不可能会用DFS去做。对于一个格子,如果他处在矩阵边界,他的邻居数量就会少于4,那么如果他的数字小于邻居数量,输出NO就完了。剩下的,我们把每个格子都改成他的邻居数量。
int n, k, m;
int a[305][305];
bool check(int i, int j)
{
return i >= 1 && i <= n && j >= 1 && j <= m;
}//判断这个点存不存在这个矩阵中,就是判断有没有这个邻居
void solve(int T)
{
cin >> n >> m;
bool f = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
int num = 0;
if (a[i][j] > 0)
{//判断4个方向的邻居
if (check(i + 1, j))num++;
if (check(i - 1, j))num++;
if (check(i, j + 1))num++;
if (check(i, j - 1))num++;
if (num < a[i][j])f = 1;
}
}
if (f)cout << "NO\n";
else
{
cout << "YES\n";
for (int i = 1; i <= n; i++, cout << endl)
for (int j = 1; j <= m; j++)
{
int num = 0;
if (check(i + 1, j))num++;
if (check(i - 1, j))num++;
if (check(i, j + 1))num++;
if (check(i, j - 1))num++;
cout << num << " ";
}
}
}
C.Element Extermination
题意:给一个数组,他是
[
1
,
n
]
[1,n]
[1,n]的一个全排列,每次我们可以选择相邻的两个数字
a
i
a_i
ai,
a
a
ai+1,其中
a
i
a_i
ai<
a
a
ai+1,然后删去其中一个,问最后能否只剩下一个数字。
我们知道,当最后的两个数字
x
x
x,
y
y
y符合
x
x
x<
y
y
y,才能成功。我们从后往前看,在能成功的前提下(即左边的数小于右边的数),我们在
x
x
x,
y
y
y的中间插入任何一个数字,都是可以化简成“只有两个数字且右边的数大于左边的数“这种情况(在
x
x
x,
y
y
y两边插入的话就不一定符合能成功的前提)。我们再以此延申至任意长度的数组,只要判断
a
1
a_1
a1是否<
a
n
a_n
an就ok了。
int n, k, m;
int a[300005];
void solve(int T)
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
if (a[1] > a[n])cout << "NO\n";
else cout << "YES\n";
}
D.Replace by MEX
题意:我们定义 m e x mex mex为当前数组中没出现过的最小非负整数,他们都在 0 0 0至 n n n之间。给一个包含n个非负整数的数组。我们每次操作可以选择一个数字,并把它替换成当前的 m e x mex mex,问使得数组呈非递减状态的操作过程。n的范围是1000,可以非常暴力得A掉。每次操作,我们找出当前的 m e x mex mex,并且把 a a a m e x mex mex的位置改成 m e x mex mex,重复该操作直到数组非递减即可。但是要注意一个特殊情况,如果当前的 m e x mex mex为 n n n,超出了数组长度,我们就要找出一个错误的位置(具体怎么才算错误,见代码)改成 m e x mex mex,再进行下面的操作。详细操作见代码。
#define pb push_back
#define vint vector<int>
int n, k, m;
int a[1005], b[1005];
void solve(int T)
{
vint ans;
cin >> n;
int mex = 0;
for (int i = 0; i < n; i++)cin >> a[i];
while (1)
{ //这里判断数组是否是非递减的
bool f = 0;
for (int i = 0; i < n - 1; i++)
if (a[i + 1] < a[i])f = 1;
if (!f)break;
//这里找出mex,很笨的方法
for (int i = 0; i < n; i++)b[i] = a[i];
sort(b, b + n);
mex = 0;
for (int i = 0; i < n; i++)
if (b[i] == mex)mex++;
//如果mex超出数组长度了
if (mex == n)
{ //找出改成mex的位置-i
int i;
for (i = 0; i < n; i++)
if (a[i] != i)break;
ans.pb(i);
a[i] = mex;
continue;
}
ans.pb(mex);
a[mex] = mex;
}
cout << ans.size() << endl;
for (int x : ans)cout << x + 1 << " ";、
//这里我们数组从0开始,所以输出要+1
cout << endl;
}
只可惜在赛场写的D没有通过fst,本来可以加100多分,最后只加了50分,心疼。比完了去看t神的D题代码,写的很清楚,这里贴一下地址。他的思路和我不一样的点在于,如果当前mex为n,直接把数组最后一个数改成mex,然后数组长度n- -,即无视掉最后一个数字,不加入后面的操作。