Codeforces Round #506 (Div. 3)
题解:数据比较小,可以暴力。当数据有1e5时,可以利用kmp的nxt数组得到最长的相同的前缀和后缀。
ps:~
题解:n条线段的相交部分一定是(Lmax,Rmin),那么我们可以暴力删除每一条线段,然后查询最大的左端点和最小的右端点,更新答案。multiset可以维护重复的元素!!!!
const int N = 300005; int n; int l[N], r[N]; multiset<int, greater<int> > L; multiset<int> R; int main() { sc(n); Rep(i, 1, n) { sc(l[i]), sc(r[i]); L.insert(l[i]); R.insert(r[i]); } int ans = 0; Rep(i, 1, n) { L.erase(L.find(l[i])); R.erase(R.find(r[i])); ans = max(ans, *R.begin() - *L.begin()); L.insert(l[i]); R.insert(r[i]); } pr(ans); return 0; }
题解:正整数a,b,ab % k = 0 等价于 a * size(b) % k + b % k = k,所以可以枚举b的长度,再用map标记一下。
ps:交换红色部分的循环顺序,就会T。(假)说明:尽量在同一个map里连续操作,避免在不同map里跳着查询。至于真正的原因,I DON'T KNOW !!!
inline void upd(int &x, int y) { x < y && (x = y); } const int N = 200005; LL n, k; LL a[N], b[N], c[N]; unordered_map<int, int> sp[12]; int get(LL x) { int cnt = 0; while(x) cnt++, x /= 10; return cnt; } int main() { IOS; cin >> n >> k; Rep(i, 1, n) { cin >> a[i]; b[i] = get(a[i]); c[i] = a[i] % k; sp[b[i]][c[i]]++; } LL cnt = 0; LL tt, tp; LL p[11]; p[1]= 10; Rep(i, 2, 10) p[i] = p[i - 1] * 10 % k; Rep(j, 1, 10) Rep(i, 1, n) { tp = (k - (p[j] % k * a[i]) % k); if (tp == k) tp = 0; tt = sp[j][tp]; if (!tt) continue; cnt += tt; if ((b[i] == j) && (tp == c[i])) cnt--; } cout << cnt << endl; return 0; }
ps:贪心,从底向上,标记节点的父亲比标记节点更优。
const int N = 2e5; int n, pa[N]; bool use[N]; vector<int> G[N], arr; void DFS(int u = 0, int d = 0, int p = 0) { pa[u] = p; for (auto v : G[u]) if (v != p) DFS(v, d + 1, u); if (d > 2) arr.pb(u); } int main() { cin >> n; rep(i, 1, n){ int u, v; cin >> u >> v; u--, v--; G[u].pb(v); G[v].pb(u); } DFS(); int ans = 0; for (auto u : arr) if (!use[u]) { ans++; for (auto v : G[pa[u]]) use[v] = 1; use[pa[u]] = 1; } cout << ans << endl; return 0; }
题解:大矩形的形状容易确定,重点在于检查其中一种颜色在当前矩形中是否能填成矩形,枚举矩形的短边,二分检查颜色a,颜色b能否组成矩形。
inline void upd(int &x, int y) { x < y && (x = y); } const int N = 100000005; LL a, b; vector<LL> s, sa, sb; void Inite() { s.clear(); sa.clear(); sb.clear(); LL x = a + b; Rep(i, 1, (int)sqrt(x)) if (x % i == 0) s.pb(i); x = a; Rep(i, 1, (int)sqrt(x)) if (x % i == 0) sa.pb(i); x = b; Rep(i, 1, (int)sqrt(x)) if (x % i == 0) sb.pb(i); } void Solve() { LL ans = INF64; for(auto x : s) { bool flag = 0; int pos1 = lower_bound(Range(sa), x) - sa.begin(); int t = (sa[pos1] == x ? x : sa[pos1 - 1]); if (a / t <= (a + b) / x) flag = 1; int pos2 = lower_bound(Range(sb), x) - sb.begin(); int o = (sb[pos2] == x ? x : sb[pos2 - 1]); if (b / o <= (a + b) / x) flag = 1; LL tp = 2 * ((a + b) / x + x); if (flag && tp < ans) ans = tp; } cout << ans << endl; } int main() { cin >> a >> b; Inite(); Solve(); return 0; }
ps:有些代码写得真的很优秀
LL a, b, c; set<LL> s; // 矩形的长(长 >= 宽)的集合 int main() { cin >> a >> b; c = a + b; LL ans = INF64; for (LL i = 1; i * i <= c; ++i) { if (a % i == 0 && i * i <= a) s.insert(a / i); if (b % i == 0 && i * i <= b) s.insert(b / i); if (c % i == 0 && c / i >= *s.begin()) ans = min(ans, 2 * (c / i + i)); // 保证了 a矩形的长 和 b矩形的长 都小于等于 c矩形的长
} cout << ans << endl; return 0; }