T1:Same
set
代码实现
n = int(input())
a = list(map(int, input().split()))
if len(set(a)) == 1:
print('Yes')
else:
print('No')
T2:3-smooth Numbers
把 \(N\) 里的 \(2\) 和 \(3\) 都除干净即可
代码实现
n = int(input())
while n%2 == 0: n /= 2
while n%3 == 0: n /= 3
if n == 1:
print('Yes')
else:
print('No')
T3:Error Correction
条件 \(4\) 就是 \(|S| = |T|\) 并且两字符串的汉明距离为 \(1\)
条件 \(2\) 和条件 \(3\) 是对称的
条件 \(2\) 就是验证 \(S\) 是否是 \(T\) 的子序列,可以用双指针实现
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int ham(string& s, string& t) {
if (s.size() != t.size()) return 999;
int res = 0;
rep(i, s.size()) if (s[i] != t[i]) res++;
return res;
}
bool f(string& s, string& t) {
if (s.size() != t.size()+1) return false;
int si = 0;
rep(ti, t.size()) {
while (si < s.size() and s[si] != t[ti]) si++;
if (si == s.size()) return false;
si++;
}
return true;
}
int main() {
int n;
string t;
cin >> n >> t;
vector<int> ans;
rep(i, n) {
string s;
cin >> s;
bool ok = false;
if (s.size()+1 >= t.size()) {
if (s == t) ok = true;
if (f(s, t)) ok = true;
if (f(t, s)) ok = true;
if (ham(s, t) == 1) ok = true;
}
if (ok) ans.push_back(i+1);
}
cout << ans.size() << '\n';
for (int i : ans) cout << i << ' ';
return 0;
}
T4:Square Permutation
枚举平方根
验证平方数是否是 \(S\) 的某个排列比较容易,可以分别对 \(S\) 和这个平方数做排序即可,或者是统计数位 \(0 \sim 9\) 的出现次数
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
string s;
cin >> n >> s;
vector<int> sc(10);
for (char c : s) sc[c-'0']++;
int ans = 0;
for (ll x = 0;; ++x) {
string t = to_string(x*x);
if (t.size() > s.size()) break;
vector<int> tc(10);
for (char c : t) tc[c-'0']++;
tc[0] += s.size()-t.size();
if (sc == tc) ans++;
}
cout << ans << '\n';
return 0;
}
T5: Joint Two Strings
对于每个 \(s\),维护两个指针 \(l\) 和 \(r\),\(l\) 表示对 \(s\) 从左到右扫描和 \(t\) 能匹配到的最多的字符个数, \(r\) 表示对 \(s\) 从右到左扫描和 \(t\) 能匹配到的最多的字符个数
然后就变成了统计满足 \(l_i + r_j \geqslant |t|\) 的 \((i, j)\) 的对数
可以通过预处理 \(r_j\) 的后缀和,然后固定 \(i\),\(O(1)\) 求 \(j\) 的个数
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
string t;
cin >> n >> t;
int m = t.size();
vector<string> s(n);
rep(i, n) cin >> s[i];
vector<int> l(n), r(n);
rep(ri, 2) {
rep(i, n) {
for (char c : s[i]) {
if (l[i] < m and t[l[i]] == c) l[i]++;
}
}
swap(l, r);
reverse(t.begin(), t.end());
rep(i, n) reverse(s[i].begin(), s[i].end());
}
vector<int> c(m+1);
rep(i, n) c[r[i]]++;
for (int i = m-1; i >= 0; --i) c[i] += c[i+1];
ll ans = 0;
for (int nl : l) ans += c[m-nl];
cout << ans << '\n';
return 0;
}
T6:Beautiful Path
注意到 \(u_i < v_i\) 保证了图是 DAG
可以考虑二分
假设答案为 \(X\)
\(\frac{\sum b}{\sum c} \geqslant X\)
\(\sum b \geqslant X\sum c\)
\(\sum b - X\sum c \geqslant 0\)
\(\sum (b-Xc) \geqslant 0\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
struct Edge {
int to, b, c;
Edge(int to=0, int b=0, int c=0): to(to), b(b), c(c) {}
};
inline void chmax(double& a, double b) { if (a < b) a = b; }
int main() {
int n, m;
cin >> n >> m;
vector<vector<Edge>> g(n);
rep(i, m) {
int u, v, b, c;
cin >> u >> v >> b >> c;
--u; --v;
g[u].emplace_back(v, b, c);
}
auto f = [&](double x) {
const double INF = 1e18;
vector<double> dp(n, -INF);
dp[0] = 0;
rep(i, n) {
for (auto e : g[i]) {
chmax(dp[e.to], dp[i]+e.b-e.c*x);
}
}
return dp[n-1] >= 0;
};
double ac = 0, wa = 1e4;
rep(ti, 50) {
double wj = (ac+wa)/2;
if (f(wj)) ac = wj; else wa = wj;
}
printf("%.10f\n", ac);
return 0;
}
T7:Generate Arrays
考虑将 \((i, A_i)\) 看做二维平面上的点
第一种操作就是纵向的分割
第二种操作就是横向的分割
可以开两个 set 分别维护 \((i, A_i)\) 和 \((A_i, i)\),然后做合并的逆向操作
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
struct D {
int l, r;
set<P> s, t;
D(int l=0, int r=0): l(l), r(r) {}
void add(int x, int y) {
s.emplace(x, y);
t.emplace(y, x);
}
void del(int x, int y) {
s.erase(P(x, y));
t.erase(P(y, x));
}
void splitX(D& d, int num) {
d = D(l, r);
if (num < s.size()/2) {
rep(i, num) {
auto [x, y] = *s.begin();
d.add(x, y);
del(x, y);
}
swap(s, d.s);
swap(t, d.t);
}
else {
num = s.size()-num;
rep(i, num) {
auto [x, y] = *s.rbegin();
d.add(x, y);
del(x, y);
}
}
}
void splitY(D& d, int val) {
val = clamp(val, l, r);
d = D(val, r);
r = val;
if (r-l < d.r-d.l) {
while (t.size()) {
auto [y, x] = *t.begin();
if (y >= r) break;
d.add(x, y);
del(x, y);
}
swap(s, d.s);
swap(t, d.t);
}
else {
while (t.size()) {
auto [y, x] = *t.rbegin();
if (y < r) break;
d.add(x, y);
del(x, y);
}
}
}
int size() { return s.size(); }
};
int main() {
int n;
cin >> n;
vector<D> d(1, D(1, n+1));
rep(i, n) {
int a;
cin >> a;
d[0].add(i+1, a);
}
int q;
cin >> q;
rep(qi, q) {
int t, s, x;
cin >> t >> s >> x;
d.push_back(D());
if (t == 1) d[s].splitX(d.back(), x);
else d[s].splitY(d.back(), x+1);
cout << d.back().size() << '\n';
}
return 0;
}