Codeforces Round 1003 (Div. 4)


A. Skibidus and Amog'u

按题意输出即可。

点击查看代码
void solve() {
  	std::string s;
  	std::cin >> s;
  	std::cout << s.substr(0, (int)s.size() - 2) + "i" << "\n";
}

B. Skibidus and Ohio

题意:给你一个字符串s,如果si==si+1。则可以删去si+1并把si随意更改。求字符串的最小长度。

如果没有一个位置满足,显然无法操作。如果至少有一个地方满足,那么因为可以随意变化si,那么可以让它每次操作后还能与前面或后面继续操作,答案为1。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    for (int i = n - 1; i > 0; -- i) {
    	if (s[i] == s[i - 1]) {
    		std::cout << 1 << "\n";
    		return;
    	}
    }
    std::cout << n << "\n";
}

C1. Skibidus and Fanum Tax (easy version) && C2. Skibidus and Fanum Tax (hard version)

题意:给你两个数组a,b,你可以把每个ai进行操作变成bjai。求能不能让数组非递减。

从后往前做,每个数都应该在不超过后一个数的同时尽可能大,设jbjaiai+1中最大的,如果ai>ai+1则使得ai=bjai,否则aiai+1ai=max(ai,bjai)。可以二分找到这个bj

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> a(n), b(m);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    for (int i = 0; i < m; ++ i) {
    	std::cin >> b[i];
    }

    std::sort(b.begin(), b.end());
    if (b.back() - a[n - 1] > a[n - 1]) {
    	a[n - 1] = b.back() - a[n - 1];
    }

    for (int i = n - 2; i >= 0; -- i) {
		int j = std::upper_bound(b.begin(), b.end(), a[i] + a[i + 1]) - b.begin() - 1;
		if (j < 0) {
			if (a[i] > a[i + 1]) {
				std::cout << "NO\n";
				return;
			}
		} else {
			if (a[i] > a[i + 1] || b[j] - a[i] > a[i]) {
				a[i] = b[j] - a[i];
			}
		}
    }
    std::cout << "YES\n";
}

D. Skibidus and Sigma

题意:给你n个数组,要将它们按某个顺序接在一起使得前缀和的和最大。

总和最大的出现在前面更优,因为它会被后面的每个位置做贡献,所以按照总和排序即可。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector a(n, std::vector<i64>(m + 1));
    for (int i = 0; i < n; ++ i) {
    	for (int j = 1; j <= m; ++ j) {
    		std::cin >> a[i][j];
    		a[i][j] += a[i][j - 1];
    	}
    }

    std::sort(a.begin(), a.end(), [&](std::vector<i64> & a, std::vector<i64> & b) {
    	return a.back() > b.back();
    });
    i64 sum = 0, ans = 0;
    for (int i = 0; i < n; ++ i) {
    	for (int j = m; j >= 1; -- j) {
    		a[i][j] -= a[i][j - 1];
    	}

    	for (int j = 1; j <= m; ++ j) {
    		sum += a[i][j];
    		ans += sum;
    	}
    }
    std::cout << ans << "\n";
}

E. Skibidus and Rizz

题意:构造一个01串,使得恰好有n个0,m个1,并且所有字串的1和0相差的最大值正好是k

如果k<abs(nm)||k>max(n,m)则无解。
否则从个数多的开始,构造k个0k个1这样的就行了。

点击查看代码
void solve() {
    int n, m, k;
    std::cin >> n >> m >> k;
    if (k < std::abs(n - m) || k > std::max(n, m)) {
    	std::cout << -1 << "\n";
    	return;
    }

    std::string ans;
    int i = (m > n);
    while (n || m) {
    	if (i & 1) {
    		int t = std::min(k, m);
    		ans += std::string(t, '1');
    		m -= t;
    	} else {
			int t = std::min(k, n);
    		ans += std::string(t, '0');
    		n -= t;
    	}
    	++ i;
    }

    std::cout << ans << "\n";
}

F. Skibidus and Slay

题意:求对于每个i,在树里是否有一条路径使得路径上节点值构成的序列里有超过一半的数字是i

因为i的个数超过了一半,你手写几个这样的序列发现每个长度为3的子序列也满足这个条件。因为它的个数超过一半了,你放一个i放一个不是i的隔着放是让i最散的放法,但这样依旧是长度为3的子序列会满足条件。
所以枚举每个点所有邻点,看有没有值相同的就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    std::vector<std::vector<int>> adj(n);
    for (int i = 1; i < n; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	-- u, -- v;
    	adj[u].push_back(v);
    	adj[v].push_back(u);
    }

    std::string s(n, '0');
    for (int u = 0; u < n; ++ u) {
    	std::set<int> set;
    	set.insert(a[u]);
    	for (auto & v : adj[u]) {
    		if (set.count(a[v])) {
    			s[a[v] - 1] = '1';
    		}

    		set.insert(a[v]);
    	}
    }

    std::cout << s << "\n";
}

G. Skibidus and Capping

题意:给你一个数组a,求有多少对数的lcm是两个质数的乘积。

先预处理筛质数,然后跑出两个质数的乘积的数。
然后排序后从前往后看。如果当前数是质数,那么它要选一个不是它的质数配对。如果他是两个质数的乘积,则它要选这两个质数或者选它自己。如果两个都不是,则和任何数的lcm都不满足条件。
记录每个数的个数和质数的个数从前往后讨论即可。

点击查看代码
const int N = 2e5 + 5;
std::vector<int> primes;
bool st[N];
int f[N];

void init(int n) {
	for (int i = 2; i <= n; ++ i) {
		if (!st[i]) {
			primes.push_back(i);
		}

		for (auto & p : primes) {
			if (p * i > n) {
				break;
			}

			st[p * i] = true;
			if (i % p == 0) {
				break;
			}
		}
	}

	for (int i = 0; i < primes.size(); ++ i) {
		for (int j = i; j < primes.size(); ++ j) {
			if ((i64)primes[i] * primes[j] > n) {
				break;
			}

			f[primes[i] * primes[j]] = primes[i];
		}
	}
}


void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    std::sort(a.begin(), a.end());
    i64 ans = 0, cntp = 0;
    std::map<int, int> cnt;
    for (int i = 0; i < n; ++ i) {
    	if (!st[a[i]]) {
    		ans += cntp - cnt[a[i]];
    		++ cntp;
    	} else if (f[a[i]]) {
    		if (a[i] / f[a[i]] == f[a[i]]) {
    			ans += cnt[f[a[i]]];
    		} else {
    			ans += cnt[f[a[i]]] + cnt[a[i] / f[a[i]]];
    		}

    		ans += cnt[a[i]] + 1;
    	}

    	cnt[a[i]] += 1;
    	// std::cout << ans << " \n"[i == n - 1];
    }

    std::cout << ans << "\n";
}


int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	init(2e5);
	int T = 1; 
	std::cin >> T;
	//scanf("%d", &T);
	while (T -- ) {
		solve();
	} 
	return 0;
}

H. Bro Thinks He's Him

题意:一个01串的价值为01段的个数,给你一个01串,求它的所有子串的价值之和。并且有q次修改,每次改变一个位置的值。

既然题目是单点修改,那么我们考虑每个点会贡献多少。
对于第i个点,它要作为01段的开头,那么前面就要选和它不一样的,固定选j后,这个j前面的位置都可选可不选,总共2j1种选法,还要算上前面什么都不选,自己开头的情况,那么左边总共有2j1+1种选法。再考虑右边,发现后面的数不管选不选都不影响i会不会做贡献,那么总共有2ni种选法,于是一个点就有(2j1+1)2ni种贡献。
现在考虑修改后怎么更新贡献。首先按上面的讨论减去这个点单独的贡献,然后这个点还会对后面的贡献有影响,因为后面的点可能选它在前面。那么他会给后面贡献2i1种选法,于是记录后面和它不一样位置的2nj,那么就要减去2i1(2nj)
然后更改后再按上面的讨论加回来就行。

点击查看代码
template <class T>
struct Fenwick {
    int n;
    std::vector<T> tr;

    Fenwick(int _n) {
        init(_n);
    }

    void init(int _n) {
        n = _n;
        tr.assign(_n + 1, T{});
    }

    void add(int x, const T &v) {
        for (int i = x; i <= n; i += i & -i) {
            tr[i] = tr[i] + v;
        }
    }

    T query(int x) {
        T res = 0;
        for (int i = x; i; i -= i & -i) {
            res = res + tr[i];
        }
        return res;
    }

    T sum(int l, int r) {
        return query(r) - query(l - 1);
    }
};

void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    std::vector<Z> p2(n + 1);
    p2[0] = 1;
    for (int i = 1; i <= n; ++ i) {
        p2[i] = p2[i - 1] * 2;
    }

    Fenwick<Z> tr10(n), tr11(n), tr20(n), tr21(n);
    Z ans = 0;
    for (int i = 1; i <= n; ++ i) {
        if (s[i - 1] == '1') {
            ans += (tr10.query(i) + 1) * p2[n - i];
            tr11.add(i, p2[i - 1]);
            tr21.add(i, p2[n - i]);
        } else {
            ans += (tr11.query(i) + 1) * p2[n - i];
            tr10.add(i, p2[i - 1]);
            tr20.add(i, p2[n - i]);
        }
    }

    auto get1 = [&](int i) -> Z {
        if (s[i - 1] == '1') {
            return (tr10.query(i) + 1) * p2[n - i];
        } else {
            return (tr11.query(i) + 1) * p2[n - i];
        }
    };

    auto get2 = [&](int i) -> Z {
        if (s[i - 1] == '1') {
            return p2[i - 1] * tr20.sum(i, n);
        } else {
            return p2[i - 1] * tr21.sum(i, n);
        }
    };

    int q;
    std::cin >> q;
    while (q -- ) {
        int i;
        std::cin >> i;
        ans -= get1(i);
        ans -= get2(i);
        if (s[i - 1] == '1') {
            tr11.add(i, -p2[i - 1]);
            tr21.add(i, -p2[n - i]);
        } else {
            tr10.add(i, -p2[i - 1]);
            tr20.add(i, -p2[n - i]);
        }

        s[i - 1] ^= 1;

        if (s[i - 1] == '1') {
            tr11.add(i, p2[i - 1]);
            tr21.add(i, p2[n - i]);
        } else {
            tr10.add(i, p2[i - 1]);
            tr20.add(i, p2[n - i]);
        }

        ans += get1(i);
        ans += get2(i);
        std::cout << ans << " \n"[!q];
    }
}
posted @   maburb  阅读(180)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示