Educational Codeforces Round 175 (Rated for Div. 2)


A. FizzBuzz Remixed

题意:求[0,n]里有多少数模3和模5的值一样。

我是打表发现每15个数的开头3个数满足要求。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::cout << n / 15 * 3 + std::min(n % 15 + 1, 3) << "\n";
}

B. Robot Program

题意:坐标轴上从起点按照给定指令序列按顺序执行,如果到了0这个位置就从头开始执行指令,问k次指令后经过了几次0。

k很大,但如果我们经过0,就会陷入一个循环。于是先求几步可以到0,然后在计算从0到0这个循环需要几步,就可以之间计算还有多少个循环可以执行。

点击查看代码
void solve() {
	i64 n, x, k;
	std::cin >> n >> x >> k;
	std::string s;
	std::cin >> s;
	i64 ans = 0;
	for (int i = 0; x != 0 && i < n && k; ++ i) {
		-- k;
		if (s[i] == 'L') {
			-- x;
		} else {
			++ x;	
		}
	}  

	if (x == 0) {
		++ ans;
		for (int i = 0; i < n; ++ i) {
			if (s[i] == 'L') {
			-- x;
			} else {
				++ x;	
			}

			if (x == 0) {
				ans += k / (i + 1);
				break;
			}
		}
	}

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

C. Limited Repainting

题意:一个序列初始都是R,每个位置有一个价值。你可以选择k个区间把位置都变成B,有一个最终序列s,如果最后你的序列和s有不一样的地方,代价就是不一样的地方的价值的最大值。求最小代价。

二分答案,如果s[i]=R && a[i]>mid则这个位置绝对不能选。否则其它可以选的位置就是一段段区间,如果一个区间有一个s[i]=B && a[i]>mid的地方就必须选。看必须选的区间数是不是小于等于k

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

    auto check = [&](int x) -> int {
    	std::vector<int> b(n);
    	for (int i = 0; i < n; ++ i) {
    		if (s[i] == 'B') {
    			b[i] = 1;
    		} else if (s[i] == 'R' && a[i] <= x) {
    			b[i] = 1;
    		}

    	}

    	int cnt = 0;
    	for (int i = 0; i < n; ++ i) {
    		if (b[i] == 1) {
    			int j = i;
    			bool flag = s[i] == 'B' && a[i] > x;
    			while (j + 1 < n && b[j + 1] == 1) {
    				++ j;
    				flag |= s[j] == 'B' && a[j] > x;
    			}

    			if (flag) {
    				++ cnt;
    			}

    			i = j;
    		}
    	}

    	return cnt <= k;
    };

    int l = 0, r = 1e9;
    while (l < r) {
    	int mid = l + r >> 1;
    	if (check(mid)) {
    		r = mid;
    	} else {
    		l = mid + 1;
    	}
    }

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

D. Tree Jumps

题意:给你一棵树,根可以到其中任意一个儿子,但从深度为2的点开始,每个点只能去深度比它大一的点,且这个点不是它到儿子。求从根开始的不同路径树。

类似DAG图路径计数,我们只能一层一层走,那么我们就一层一层算,当前点可以从上一层除了父亲过了,那么记录到达每个点的路径数f,以及每一层的点的路径数总和sum,则以该点为终点的路径数为sumfpi。其中pii的父亲。

代码省略了取模类

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::vector<int>> adj(n);
    std::vector<int> p(n);
    for (int i = 1; i < n; ++ i) {
    	std::cin >> p[i];
    	-- p[i];
    	adj[p[i]].push_back(i);
    }

    std::vector<int> d(n);
    std::vector<std::vector<int>> g(n);
    auto dfs = [&](auto self, int u) -> void {
    	g[d[u]].push_back(u);
    	for (auto & v : adj[u]) {
    		d[v] = d[u] + 1;
    		self(self, v);
    	}
    };

    dfs(dfs, 0);
    std::vector<Z> f(n);
    Z sum = 0;
    for (auto & u : adj[0]) {
    	f[u] = 1;
    	sum += 1;
    }

    Z ans = sum + 1;

    for (int i = 2; i < n; ++ i) {
    	Z t = 0;
    	for (auto & u : g[i]) {
    		f[u] = sum - f[p[u]];
    		t += f[u];
    	}

    	sum = t;
    	ans += t;
    }

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

E. Game with Binary String

题意:AliceBob01串上做游戏,Alice先手。Alice只能拿"00",Bob只能拿其它的。给你一个01串,求有多少子串使得Alice能赢。

首先Bob肯定优先拿"01"和"10",因为这样可以最大程度断Alice的操作。那么每次Alice拿两个0Bob拿一个0一个1,一轮就减少三个0一个1,那么如果Alice想赢,0的数量至少得是1的数量的三倍多两个。假设cnt03×cnt1+2,那么只要满足这个条件就是可以的,最极端的情况是"1010101000..."这种,这样可以让Alice操作数最小,但我们本来就让给了cnt10Bob,所以这个情况也是赢。但还有一个情况,就是cnt0=3×cnt11,这种情况就是"010"这种,操作完后Bob只剩一个1,无法操作,也是Alice赢。
于是我们记录每个前缀的值sumi,等于0的地方就+1,否则3,这样就表示了cnt03×cnt1,对于每个位置,相当于找sumisumj2以及sumisumj=1的地方。用树状数组维护维护值域即可。由于有负数,需要整体右移。

点击查看代码
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{};
        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() {
    int n;
    std::cin >> n;
    std::string s;
    std::cin >> s;

    const int D = 3 * n + 10;
    std::vector<int> sum(n + 1);
    sum[0] = D;
    for (int i = 0; i < n; ++ i) {
    	sum[i + 1] = sum[i] + (s[i] == '0' ? 1 : -3);
    }

    Fenwick<int> tr(D * 2);
    tr.add(sum[0], 1);
    i64 ans = 0;
    for (int i = 1; i <= n; ++ i) {
    	ans += tr.sum(sum[i] + 1, sum[i] + 1);
    	ans += tr.query(sum[i] - 2);
    	tr.add(sum[i], 1);
    }

    std::cout << ans << "\n";
}
posted @   maburb  阅读(596)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示