牛客周赛 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];
	}
}
posted @ 2025-04-27 21:00  maburb  阅读(102)  评论(0)    收藏  举报