Codeforces Round 839 (Div. 3) vp总结
小菜鸡的VP总结

C. Different Differences
- 题意:包含k个整数的数组a,是严格单调递增的,定义“特征”为a中元素两两相减后所构成数组[a2-a1,a3-a2,...,ak-a(k-1)]中不同的数字个数。给出一个k和n你需要构造出一个最大“特征”数的数组a,其中数字只能在1-n的范围内。
- 思路:观察样例可以发现将a元素中的元素两两相减后所构成的数组加起来即为n,所以可以将1和n放在首位和末位,计算除去它们的差值,并按照+1 +2 +3的方式,构造第二位第三位第四位...而后将不足的+1即可
void BlueFire()
{
int k, n;
cin >> k >> n;
int x = n - 1;
vector<int> v(k + 1);
v[1] = 1;
v[k] = n;
for (int i = 2; i <= k - 1; i++)
v[i] = 1;
int cz = x - (k - 2);
int lstIndex = -1;
for (int i = 2, j = 1; i <= k - 1; i++)
{
if (cz < j)
{
lstIndex = i;
break;
}
v[i] = v[i - 1] + j;
cz -= j;
j++;
}
if (lstIndex != -1)
for (int i = lstIndex; i <= k - 1; i++)
v[i] = v[i - 1] + 1;
for (int i = 1; i <= k - 1; i++)
cout << v[i] << " ";
cout << v[k] << endl;
return;
}
D. Absolute Sorting
- 题意:给出一个包含n个整数的a数组,当数组呈递增时视为已排序。执行一次操作:选择一个数x,将数组里的每个数都替换为这个数和x做差的绝对值,找出可以让a数组排序的x。
- 思路:观察后发现这个x应该是非递增的两个相邻数加起来除以2向上取整,然后取最大值,当然要注意找到x后还要计算一遍,如果不符合就要输出-1(无法排序)
void BlueFire()
{
int n;
cin >> n;
vector<ll> v(n + 1);
for (int i = 1; i <= n; i++)
cin >> v[i];
ll minn = 0;
for (int i = 1; i <= n - 1; i++)
{
if (v[i] > v[i + 1])
{
ll x = ((v[i + 1] + v[i]) % 2 == 0 ? (v[i + 1] + v[i]) / 2 : (v[i + 1] + v[i]) / 2 + 1);
if (x > minn)
minn = x;
}
}
for (int i = 1; i <= n; i++)
v[i] = abs(v[i] - minn);
for (int i = 1; i <= n - 1; i++)
if (v[i] > v[i + 1])
{
cout << -1 << endl;
return;
}
cout << minn << endl;
return;
}
E. Permutation Game
- 题意:两个玩家玩一个游戏,给出一组包含n个数字的排列,所有的数字一开始都是红色,每名玩家可以执行三种操作:
1.重新排列蓝色的数字
2.将一个红色的数字变为蓝色
3.跳过本回合
先手的获胜条件是这个排列变为升序排列,后手的获胜条件是变为降序排列,你需要给出最后获胜的玩家
- 思路:假设是先手,要变为升序排列(1,2...n),那么对应位置上的数如果不是升序排列的数,为了获胜先手一定会将其变为蓝色(为了把那个正确的数交换过来),同理后手也是,对自己最优的策略一定是先将不符合降序的数变为蓝色再交换,因此我们要计算先手和后手一定要变色的数然后比对即可,如果都不属于两种情况,就是需要拿来交换的数字,也要计算。注意平局的情况。
void BlueFire()
{
int n;
cin >> n;
vector<int> v(n + 1);
for (int i = 1; i <= n; i++)
cin >> v[i];
int cnt1 = 0, cnt2 = 0, cnt = 0;
for (int i = 1; i <= n; i++)
{
if (v[i] == i)
cnt2++;
else if (v[i] == n - i + 1)
cnt1++;
else
cnt++;
}
if (cnt1 + cnt <= cnt2)//先手所以有等号
cout << "First" << endl;
else if (cnt2 + cnt < cnt1)
cout << "Second" << endl;
else
cout << "Tie" << endl;
return;
}
F. Copy of a Copy of a Copy
- 题意:给出一个n*m的01矩阵,每次可以进行如下操作:选择一个位置,该位置四个方向的01情况与该位置不同,将该位置01变换,创建改变后的拷贝矩阵。现在给出k个拷贝矩阵和原矩阵,但是顺序并不是按照操作顺序的,现在需要找出初始矩阵,并输出操作方案。
- 思路:能修改的地方最多的一定是最初的,根据这种规则排序,依次比较不同的地方即可
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
struct node
{
char g[40][40];
int id, cnt;
} mp[105];
void BlueFire()
{
int n, m, k;
cin >> n >> m >> k;
k++;
for (int i = 1; i <= k; i++)
{
mp[i].id = i;
for (int j = 1; j <= n; j++)
for (int p = 1; p <= m; p++)
cin >> mp[i].g[j][p];
for (int j = 2; j < n; j++)
for (int p = 2; p < m; p++)
{
bool flag = 0;
for (int q = 0; q < 4; q++)
{
int tx = j + dx[q], ty = p + dy[q];
if (tx > n || ty > m || tx <= 0 || ty <= 0)
{
flag = 1;
break;
}
if (mp[i].g[tx][ty] == mp[i].g[j][p])
{
flag = 1;
break;
}
}
if (!flag)
mp[i].cnt++;
}
}
sort(mp + 1, mp + 1 + k, [](node &a, node &b)
{ return a.cnt > b.cnt; });
vector<PII> ans;
for (int i = 2; i <= k; i++)
{
for (int j = 1; j <= n; j++)
for (int p = 1; p <= m; p++)
{
if (mp[i].g[j][p] != mp[i - 1].g[j][p])
ans.push_back({j, p});
}
ans.push_back({-1, mp[i].id});
}
cout << mp[1].id << endl;
cout << ans.size() << endl;
for (auto c : ans)
{
if (c.first == -1)
cout << 2 << " " << c.second << endl;
else
cout << 1 << " " << c.first << " " << c.second << endl;
}
return;
}