VP Educational Codeforces Round 8


A. Tennis Tournament

按题意模拟。

点击查看代码
void solve() {
 	int n, b, p;
 	std::cin >> n >> b >> p;
 	int ans1 = 0, ans2 = n * p;
 	while (n > 1) {
 		int k = 1;
 		while (k * 2 <= n) {
 			k *= 2;
 		}

 		ans1 += b * k + k / 2;
 		n -= k / 2;
 	}   

 	std::cout << ans1 << " " << ans2 << "\n";
}

B. New Skateboard

题意:给你一个数字字符串,求这个字符串中有多少子串能被4整除。

末尾两位能被4整除,则这个数能被4整除。假设这个数为dt×10t1+dt1×10t2+...+d2×101+d1×100,那么就等于(dt×10t3+dt1×10t4+...)×100+d2×101+d1×100,那么因为4|100,则4|(dt×10t3+dt1×10t4+...)×100,同理因为4|d2×101+d1×100 所以得到4|(dt×10t3+dt1×10t4+...)×100+d2×101+d1×100

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    i64 ans = 0;
    for (int i = 0; i < n; ++ i) {
    	if ((s[i] - '0') % 4 == 0) {
    		++ ans;
    	}

    	if (i && ((s[i - 1] - '0') * 10 + s[i] - '0') % 4 == 0) {
    		ans += i;
    	}
    }

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

C. Bear and String Distance

题意:两个长度相同的字符的值定义为对应位置的字符之间相差字符的个数。现在给你一个字符串s,要求构造一个和s的值为k的字符串。

因为可以取相等的字符,其位置上贡献是0,那么我们可以贪心让前面的取尽量大的差距。

点击查看代码
void solve() {
    int n, k;
    std::cin >> n >> k;
    std::string s;
    std::cin >> s;
    for (auto & c : s) {
    	int x = 'z' - c, y = c - 'a';
    	if (x >= y && k >= x) {
    		c += x;
    		k -= x;
    	} else if (y >= x && k >= y) {
    		c -= y;
    		k -= y;
    	} else {
    		if (x >= k) {
    			c += k;
    			k = 0;
    		} else {
    			c -= k;
    			k = 0;
    		}
    	}
    }

    if (k > 0) {
    	std::cout << -1 << "\n";
    	return;
    }

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

D. Magic Numbers

题意:求[a,b]之间有多少个数字满足,d仅出现在所有偶数位置,且这个数字能被m整除。

考虑数位dpf[u][x][st]表示到了第u个位置模mx且当前位置是奇数还是偶数。然后就是按照数位dp经典套路求[0,b][0,a1]的值就行了。

点击查看代码
const int mod = 1e9 + 7;

void solve() {
	int m, d;
	std::cin >> m >> d;
	std::string a, b;
	std::cin >> a >> b;
	auto work = [&](std::string & s) -> int {
		int n = s.size();
		std::vector f(n, std::vector(m, std::array<int, 2>{-1, -1}));
		auto dfs = [&](auto self, int u, int x, bool st, bool zero, bool limit) -> int {
			if (u == n) {
				return x == 0;
			}

			if (!limit && !zero && f[u][x][st] != -1) {
				return f[u][x][st];
			}

			int up = limit ? s[u] - '0' : 9;
			int res = 0;
			if (!zero && st) {
				if (up >= d) {
					res = self(self, u + 1, (x * 10 + d) % m, false, false, limit && d == up);
				}
			} else {
				for (int i = 0; i <= up; ++ i) {
					if (!(i == 0 && zero) && i == d) {
						continue;
					}
					res = (res + self(self, u + 1, (x * 10 + i) % m, !(i == 0 && zero), i == 0 && zero, limit && i == up)) % mod;
				}
			}

			if (!limit && !zero) {
				f[u][x][st] = res;
			}

			return res;
		};

		return dfs(dfs, 0, 0, false, true, true);
	};


	int ans = 0;
	if (a == "0") {
		ans = work(b);
	} else {
		std::reverse(a.begin(), a.end());
		for (int i = 0; i < a.size(); ++ i) {
			if (a[i] == '0') {
				a[i] = '9';
			} else {
				-- a[i];
				break;
			}
		}

		if (a.back() == '0') {
			a.pop_back();
		}

		std::reverse(a.begin(), a.end());
		ans = (work(b) - work(a) + mod) % mod;
	}

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

E. Zbazi in Zeydabad

题意:定义一个z形为一个正方形矩阵内反对角线以及第一行和最后一行全是z。求给出的字符矩阵中有多少z形。

预处理l[i][j],r[i][j],ld[i][j]表示i,j往左往右和往左下有多少连续的z
考虑枚举z形的右上角i,j,那么就是要求有多少和它一个对角线上并且在它下面且往右边可以延伸到大于等于j的位置。发现直接枚举复杂度较高,考虑优化枚举顺序,按列从右往左枚举,然后把同一条对角线上所有满足条件的点标为1,那么对于i,j就是求对角线上[i,r]中有多少1,其中r=i+min(l[i][j],ld[i][j])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, m;
    std::cin >> n >> m;
    std::vector<std::string> s(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> s[i];
    }

    std::vector l(n, std::vector<int>(m));
    std::vector r(n, std::vector<int>(m));
    std::vector ld(n, std::vector<int>(m));
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < m; ++ j) {
    		if (s[i][j] == 'z') {
    			if (j == 0) {
    				l[i][j] = 1;
    			} else {
    				l[i][j] = l[i][j - 1] + 1;
    			}
    		}
    	}

    	for (int j = m - 1; j >= 0; -- j) {
    		if (s[i][j] == 'z') {
    			if (j == m - 1) {
    				r[i][j] = 1;
    			} else {
    				r[i][j] = r[i][j + 1] + 1;
    			}
    		}
    	}
    }

    for (int i = n - 1; i >= 0; -- i) {
    	for (int j = 0; j < m; ++ j) {
    		if (s[i][j] == 'z') {
    			if (i == n - 1 || j == 0) {
    				ld[i][j] = 1;
    			} else {
    				ld[i][j] = ld[i + 1][j - 1] + 1;
    			}
    		}
    	}
    }

    std::vector<std::vector<std::pair<int, int>>> a(m);
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < m; ++ j) {
    		if (s[i][j] == 'z') {
    			a[j + r[i][j] - 1].push_back({i, j});
    		}
    	}
    }

    std::vector<Fenwick<int>> tr(n + m, Fenwick<int>(n + 1));
    i64 ans = 0;
    for (int j = m - 1; j >= 0; -- j) {
    	for (auto & [x, y] : a[j]) {
    		tr[x + y].add(x + 1, 1);
    	}

    	for (int i = 0; i < n; ++ i) {
    		if (s[i][j] == 'z') {
    			int len = std::min(l[i][j], ld[i][j]);
    			int l = i, r = i + len - 1;
    			ans += tr[i + j].sum(l + 1, r + 1);
    		}
    	}
    }

    std::cout << ans << "\n";
}
posted @   maburb  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示