Codeforces 1312 Div.2 笔记(1)
感想
感觉半夜打比赛很多时候脑子转不过来,看懂了A-E的题面,剩下两道题还需琢磨,C题起床之后就想到做法然而赛场上没有想出来;B题初步猜到结论然而没有敢往上写,只是交上了一个部分分。心态还是要调整,还有做题技巧还要提高。
题目
A Two Regular Polygons
解析
给定一个凸正 边形 ,问可不可以在里面内嵌一个正 边形 ,使得 的顶点全部都是 的顶点,且 的中心和 的中心重合。
无非就是判断 的顶点去掉 个之后剩下的顶点数是否还是 的整数倍,3分钟切。
代码
#include <bits/stdc++.h>
typedef long long ll;
ll nextInt()
{
ll num = 0;
char c = 0;
bool flag = false;
while ((c = std::getchar()) == ' ' || c == '\r' || c == '\t' || c == '\n');
if (c == '-')
flag = true;
else
num = c - 48;
while (std::isdigit(c = std::getchar()))
num = num * 10 + c - 48;
return (flag ? -1 : 1) * num;
}
bool ok(const int n, const int m)
{
if (n < 6)
return false;
int t = n - m;
if (t % m == 0)
return true;
return false;
}
int main(int argc, char **argv)
{
int T = nextInt();
while (T--)
{
int n = nextInt(), m = nextInt();
if (ok(n, m))
std::cout << "YES\n";
else
std::cout << "NO\n";
}
}
B Bogosort
解析
给定一个数组 ,若对于任何 则称这个数组为好的。给出几组数问如何调整才能调整成好数组。
一开始想到全排列挨个试,虽然最大复杂度 但是感觉有机会,但不出所料TLE。后来想到是不是排序后倒序输出就好,但没敢试就结束了。最后查看他人AC代码果然是这样。感觉以后要大胆写。
代码
int main(int argc, char **argv)
{
int t = nextInt();
while (t--)
{
int n = nextInt();
for (int i = 1; i <= n; i++)
a[i] = nextInt();
std::sort(a + 1, a + n + 1);
for (int i = n; i >= 1; i--)
std::cout << a[i] << ' ';
std::cout << '\n';
}
return 0;
}
C Adding Powers
解析
给定 数组全是0,给定一个数 ,你可以有若干操作步骤,第 次将 中的某一元素加上 ,给定 数组,问若干次操作后 可不可以变成 。
初步想法是拆数,将每个 拆成 然后判断是否有重复。后来不知为何一直wa。早晨起来一改竟然过了。
代码
#include <bits/stdc++.h>
typedef long long ll;
ll nextInt()
{
ll num = 0;
char c = 0;
bool flag = false;
while ((c = std::getchar()) == ' ' || c == '\r' || c == '\t' || c == '\n');
if (c == '-')
flag = true;
else
num = c - 48;
while (std::isdigit(c = std::getchar()))
num = num * 10 + c - 48;
return (flag ? -1 : 1) * num;
}
const size_t _Siz = 1922;
ll a[_Siz];
int main(int argc, char **argv)
{
int T = nextInt();
while (T--)
{
int n = nextInt(), m = nextInt();
std::memset(a, 0, sizeof a);
for (int i = 1; i <= n; i++)
{
ll x = nextInt();
ll pos = 0;
while (x != 0) // 问题在这里,wa版本这里写的是while (x % m)
{
a[++pos] += x % m;
x /= m;
}
}
bool flag = true;
for (int i = 1; i <= 100; i++)
if (a[i] > 1)
{
std::cout << "NO\n";
flag = false;
break;
}
if (flag)
std::cout << "YES\n";
}
}
D Count the Arrays
解析
给定 个数的数组 ,对于任意整数 都满足 ,求有多少种方法使得数组中存在一个 ,使得 前面的数严格递增, 后面的数严格递减。
比赛时打眼一看推公式就跳过去了没做。早上起来推了半天没有思路,看别人的AC代码发现是推组合数或者倍增。自己推了一遍,具体思路如下:
首先,
不能在第一位和最后一位,所以从第2到n - 1每一位都可以放最大值
,放上之后左右两边分别可以有
和
种放数的方法,然后最大值可以有
种情况,所以要乘
。QED.
代码
#include <bits/stdc++.h>
typedef long long ll;
ll nextInt()
{
ll num = 0;
char c = 0;
bool flag = false;
while ((c = std::getchar()) == ' ' || c == '\r' || c == '\t' || c == '\n');
if (c == '-')
flag = true;
else
num = c - 48;
while (std::isdigit(c = std::getchar()))
num = num * 10 + c - 48;
return (flag ? -1 : 1) * num;
}
const size_t _Siz = 1992332;
ll kysumi(ll n, ll m, const ll p)
{
n = (n % p + p) % p;
ll ans = 1;
while (m)
{
if (m & 1)
ans = ans * n % p;
n = n * n % p;
m >>= 1;
}
return ans;
}
ll fac[_Siz] = { 0 };
const ll M = 998244353;
void Fact()
{
fac[0] = 1;
fac[1] = 1;
for (int i = 2; i <= _Siz - 4; i++)
fac[i] = i * fac[i - 1] % M;
}
ll C(const ll n, const ll m)
{
return fac[n] * kysumi(fac[n-m] * fac[m] % M, M - 2, M) % M;
}
int main(int argc, char **argv)
{
Fact();
// ll T = nextInt();
// while (T--)
// {
ll ans = 0;
ll n = nextInt(), m = nextInt();
for (int i = 2; i <= n - 1; i++)
ans = (ans + C(m, n - 1) * C(n - 2, i - 2) % M * (n - i) % M) % M;
std::cout << ans << std::endl;
// }
return 0;
}
E Array Shrinking
解析
给定一个数组,如果这个数组里有两个数 和 相同,那么可以把这个两个数替换成一个数 。问执行若干遍操作之后数组最短是多少。
比赛现场的时候就纯暴力模拟这个过程,不出所料wa了第5个点。感觉是dp,然而没有推出正确的方程。早上起来列了个表之后推出做法了:
用f[i, j]代表起点为i,终点为j的子区间,如果可以合并的话该值为合并后的值,否则为0。枚举长度和左节点i,如果可以合并的话取最小值dp[i]。
代码
#include <bits/stdc++.h>
typedef long long ll;
ll nextInt()
{
ll num = 0;
char c = 0;
bool flag = false;
while ((c = std::getchar()) == ' ' || c == '\r' || c == '\t' || c == '\n');
if (c == '-')
flag = true;
else
num = c - 48;
while (std::isdigit(c = std::getchar()))
num = num * 10 + c - 48;
return (flag ? -1 : 1) * num;
}
const size_t _Siz = 622;
ll a[_Siz] = { 0 }, b[_Siz] = { 0 }, n, m;
ll f[_Siz][_Siz], dp[_Siz];
int main(int argc, char **argv)
{
n = nextInt();
for (int i = 1; i <= n; i++)
{
a[i] = nextInt();
f[i][i] = a[i];
}
for (int len = 2; len <= n; len++)
for (int l = 1; l <= n - len + 1; l++)
{
int r = l + len - 1;
for (int k = l; k <= r; k++)
{
if (f[l][k] && f[k + 1][r] && f[l][k] == f[k + 1][r])
f[l][r] = f[l][k] + 1;
}
}
std::memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j < i; j++)
if (f[j + 1][i])
dp[i] = std::min(dp[i], dp[j] + 1);
std::cout << dp[n] << std::endl;
return 0;
}