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 里的 23 都除干净即可

代码实现
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 和这个平方数做排序即可,或者是统计数位 09 的出现次数

代码实现
#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,维护两个指针 lrl 表示对 s 从左到右扫描和 t 能匹配到的最多的字符个数, r 表示对 s 从右到左扫描和 t 能匹配到的最多的字符个数
然后就变成了统计满足 li+rj|t|(i,j) 的对数
可以通过预处理 rj 的后缀和,然后固定 iO(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

注意到 ui<vi 保证了图是 DAG

可以考虑二分

假设答案为 X
bcX
bXc
bXc0
(bXc)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,Ai) 看做二维平面上的点
第一种操作就是纵向的分割
第二种操作就是横向的分割

可以开两个 set 分别维护 (i,Ai)(Ai,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;
}