牛客周赛 Round 91
A. while
点击查看代码
void solve() {
std::string s;
std::cin >> s;
std::string t = "while";
int ans = 0;
for (int i = 0; i < 5; ++ i) {
ans += s[i] != t[i];
}
std::cout << ans << "\n";
}
B. token
枚举就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
i64 ans = 0;
for (int i = 0; i < n; ++ i) {
i64 sum = 0;
for (int j = std::max(0, i - 9); j <= i; ++ j) {
sum += a[j];
}
ans = std::max(ans, sum);
}
std::cout << ans << "\n";
}
C. 小苯的逆序对和
题意:找最大的逆序对的和。
记录前面最大的数,如果比当前数大,就更新答案。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int pre = 0;
int ans = 0;
for (int i = 0; i < n; ++ i) {
if (pre > a[i]) {
ans = std::max(ans, pre + a[i]);
}
pre = std::max(pre, a[i]);
}
std::cout << ans << "\n";
}
D. 数组4.0
题意:如果\(|a_i - a_j| = 1\),则\(i, j\)连边。求使得所有位置在一个联通块需要再加几条边。
连续一些数会在一个联通块里,求出有几个这样的联通块,就需要联通块个数减一条边。然后如果一个联通块只有一个数,那么这个数出现多少次就要往外连几条边。关于求联通块个数,可以看有多少个\(x\)存在而\(x+1\)不存在。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::map<int, int> cnt;
for (auto & x : a) {
++ cnt[x];
}
int ans = 0;
for (auto & [x, y] : cnt) {
if (!cnt.count(x - 1) && !cnt.count(x + 1)) {
ans += y - 1;
}
ans += !cnt.count(x + 1);
}
-- ans;
std::cout << ans << "\n";
}
E. 小苯的矩阵反转
题意:一个\(01\)矩阵,每次操作两行或者两列或者一行一列。使得对应行列反转。求能不能使得矩阵全是\(0\)。
枚举这三种操作就行。记录每行\(1\)的个数和每列\(1\)的个数以及\(1\)的总个数。对于操作两行,只需要满足\(sum\)是一行数的两倍,以及正好有两行全是\(1\)的行就行,列同理。对于操作一行一列,需要满足有一个位置是\(0\),他这一行一列除了它都是\(1\)。
还有全\(0\)也是合法的。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<int> row(n), col(m);
std::vector<std::string> a(n);
int sum = 0;
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
row[i] = std::ranges::count(a[i], '1');
for (int j = 0; j < m; ++ j) {
col[j] += a[i][j] == '1';
}
sum += row[i];
}
if (sum == 0) {
std::cout << "YES\n";
return;
}
for (int i = 0; i < n; ++ i) {
for (int j = i + 1; j < n; ++ j) {
if (row[i] == m && row[j] == m && row[i] + row[j] == sum) {
std::cout << "YES\n";
return;
}
}
}
for (int i = 0; i < m; ++ i) {
for (int j = i + 1; j < m; ++ j) {
if (col[i] == n && col[j] == n && col[i] + col[j] == sum) {
std::cout << "YES\n";
return;
}
}
}
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
if (a[i][j] == '0' && row[i] + col[j] == sum && row[i] == m - 1 && col[j] == n - 1) {
std::cout << "YES\n";
return;
}
}
}
std::cout << "NO\n";
}
F. 小苯的因子查询
题意:求\(n!\)的奇数因子个数除总因子个数的值。
我们知道对于一个数\(n = p_1^{a_1}p_2^{a_2}...p_k^{a_k}\),它的因子个数是\(\prod_{i=1}^{k} (a_i + 1)\)。它的奇数因子不包含\(2\), 假设\(p_1 = 2\),那么奇数因子有\(\prod_{i=2}^{k} (a_i + 1)\)个,则奇数因子的概率为\(\frac{\prod_{i=1}^{k} (a_i + 1)}{\prod_{i=2}^{k} (a_i + 1)} = \frac{1}{a_1 + 1}\)。那么我们只需要求出\(2\)在质因子分解里出现多少次就行。具体就是每个数一直除二得到每个数里\(2\)这个因子的个数,然后记一下前缀和。也可以用__builtin_ctz直接算。
点击查看代码
const int N = 1e6 + 5, mod = 998244353;
int inv[N], sum[N];
void init(int n) {
inv[1] = 1;
for (int i = 2; i <= n; ++ i) {
inv[i] = (i64)(mod - mod / i) * inv[mod % i] % mod;
}
for (int i = 1; i <= n; ++ i) {
sum[i] = sum[i - 1] + __builtin_ctz(i);
}
}
void solve() {
init(1e6 + 1);
int t;
std::cin >> t;
while (t -- ) {
int n;
std::cin >> n;
int ans = inv[sum[n] + 1];
std::cout << ans << " \n"[!t];
}
}

浙公网安备 33010602011771号