SMU Summer 2024 Contest Round 2(7.9)
A Sierpinski carpet
思路:考虑把每一级的结构存下来,每一级都由3*3个上一级的结构推出的。先推出第一层1*3的结构,后面两层2*3直接复制1*3的结构,再找到中心位置赋值成白色即可
void solve() {
vector<vector<string> > ve(10, vector<string> (1000, "") );
ve[1][1] = "###";
ve[1][2] = "#.#";
ve[1][3] = "###";
ve[2][1] = "#########";
ve[2][2] = "#.##.##.#";
ve[2][3] = "#########";
ve[2][4] = "###...###";
ve[2][5] = "#.#...#.#";
ve[2][6] = "###...###";
ve[2][7] = "#########";
ve[2][8] = "#.##.##.#";
ve[2][9] = "#########";
int n;
cin >> n;
if (n == 0) {
cout << "#";
return ;
}
for (int p = 3; p <= n; ++p) {
for (int i = 1; i <= pow(3, p - 1); ++i) {
ve[p][i] = ve[p - 1][i] + ve[p - 1][i] + ve[p - 1][i];
}
int s = pow(3, p - 1);
for (int i = 1; i <= pow(3, p - 1); ++i) {
ve[p][i + s] = ve[p][i];
ve[p][i + s + s] = ve[p][i];
}
for (int i = s + 1; i < s + s + 1; ++i) {
for (int j = s + 1; j < s + s + 1; ++j) {
ve[p][i][j - 1] = '.';
}
}
}
for (int i = 1; i <= pow(3, n); ++i) {
cout << ve[n][i] << '\n';
}
}
B Consecutive
思路:先找出哪些位置是合法的,维护前缀和即可(注意不能算上右边界的贡献)
void solve() {
int n, q;
cin >> n >> q;
string s;
cin >> s;
s = ' ' + s;
vector<int> ve(n + 5);
for (int i = 1; i < n; ++i) {
if (s[i] == s[i + 1]) ve[i] = 1;
ve[i] += ve[i - 1];
}
for (int i = 0; i < q; ++i) {
int l, r;
cin >> l >> r;
cout << ve[r - 1] - ve[l - 1] << '\n';
}
}
C Minimum Width
思路:首先应该把题目读清楚(刚开始读假了,顺序是已经定好的,那问题就简单了),二分W,按顺序判断单词是否都能放下即可
void solve() {
int n, m;
cin >> n >> m;
vector<int> ve(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> ve[i];
}
// sort(ve.begin() + 1, ve.end());
int l = 1, r = 1e15, ans;
auto check = [=] (int x) {
int res = 1, now = 0;
for (int i = 1; i <= n; ++i) {
if (ve[i] > x) return false;
if (now == 0) now += ve[i];
else {
if (now + ve[i] + 1 <= x) {
now += 1 + ve[i];
} else {
res ++;
now = ve[i];
}
}
}
return res <= m;
};
while (l <= r) {
int mid = l + r >> 1;
if (check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
cout << ans;
}
D Printing Machine
思路:贪心,按时间来考虑,先处理先进到打印机里的文件,若有多个文件,则先处理最先退出打印机的文件
void solve() {
int n;
cin >> n;
vector<PII> ve(n);
for (int i = 0; i < n; ++i) {
cin >> ve[i].first >> ve[i].second;
ve[i].second += ve[i].first;
}
sort(ve.begin(), ve.end());
priority_queue<int, vector<int>, greater<int> > q;
int res = 0, now = 0, idx = 0;
while (q.size() || idx < n) {
while (idx < n && ve[idx].first <= now) {
q.push(ve[idx++].second);
}
if (q.size()) {
res ++, now ++, q.pop();
}
while (q.size() && q.top() < now) q.pop();
if (q.empty() && idx < n) {
now = ve[idx].first;
}
}
cout << res;
}
E Nearest Black Vertex
思路:n的范围2e3,分两步:
1.把距离pi距离小于di的点都标为白色,bfs每个pi
2.把距离pi刚好为di的点(非白色)都标为黑色,若某个pi不存在这样的黑点则No,bfs每个pi
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int, int>
//#define double long double
const int N = 2e5 + 5, mod = 1e9 + 7;
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int> > ve(n + 1);
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
ve[u].push_back(v), ve[v].push_back(u);
}
int k;
cin >> k;
if (k == 0) {
cout << "Yes\n";
cout << "1";
for (int i = 2; i <= n; ++i) cout << "0";
return ;
}
vector<int> col(n + 1), p(k), d(k);
auto bfs = [&] (int u, int dis) {
vector<int> vis(n + 1);
queue<PII> q;
q.push({u, 0});
vis[u] = 1;
while (q.size()) {
auto t = q.front();
q.pop();
if (t.second < dis) col[t.first] = -1;
if (t.second + 1 < dis) {
for (auto v:ve[t.first]) {
if (vis[v]) continue;
vis[v] = 1;
q.push({v, t.second + 1});
}
}
}
};
for (int i = 0; i < k; ++i) {
cin >> p[i] >> d[i];
bfs(p[i], d[i]);
}
bool ok = true;
auto bfs1 = [&] (int u, int dis) {
bool is = false;
queue<PII> q;
vector<int> vis(n + 1);
q.push({u, 0});
vis[u] = 1;
while(q.size()) {
auto t = q.front();
q.pop();
if (t.second == dis) {
if (col[t.first] == 1) is = true;
if (col[t.first] != -1) {
col[t.first] = 1;
is = true;
}
continue;
}
for (auto v:ve[t.first]) {
if (vis[v]) continue;
vis[v] = 1;
q.push({v, t.second + 1});
}
}
return is;
};
for (int i = 0; i < k; ++i) {
ok = bfs1(p[i], d[i]);
if (!ok) break;
}
if (ok) {
cout << "Yes\n";
for (int i = 1; i <= n; ++i) {
if (col[i] == 1) cout << "1";
else cout << "0";
}
} else cout << "No";
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
while (T --) {
solve();
}
return 0;
}
F Christmas Present 2
思路:可以随时回去补充礼物并按顺序送完,dp做法
f[i]表示,送完1~i并且最后回家的最小路径,考虑从上一次回家补充转移过来:f[i] = min ( f[j] + dis[st -> j+1] + dis[j+1 -> i] + dis[i ->st] ),其中i-k <= j <= i-1
这里dis[j+1 -> i]可以用前缀和求出,即sum[i] - sum[j+1],最后调整下式子,将关于j的放在一边:f[i] = min ( ( f[j] + dis[j+1 -> i] - sum[j+1] )+ sum[i] + dis[i ->st] )
如果枚举j复杂度是n2的,这里从式子可以看出f[j] + dis[j+1 -> i] - sum[j+1] 可以用单点队列维护,这样复杂度就是n的
#include <bits/stdc++.h>
using namespace std;
#define int long long
//#define double long double
#define PII pair<int, int>
#define PDI pair<double, int>
const int N = 2e5 + 5, mod = 1e9 + 7;
struct E{
double x, y;
};
void solve() {
int n, k;
cin >> n >> k;
vector<E> ve(n + 5);
auto dis = [] (E a, E b) {
double d = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
return (double)sqrt(d);
};
for (int i = 0; i <= n; ++i) cin >> ve[i].x >> ve[i].y;
vector<double> stoi(n + 5), sum(n + 5), f(n + 5);
for (int i = 1; i <= n; ++i) {
stoi[i] = dis(ve[0], ve[i]);
if (i > 1)
sum[i] = sum[i - 1] + dis(ve[i], ve[i - 1]);
}
deque<PDI> q;
q.push_back({ f[0] + stoi[1] - sum[1], 0});
for (int i = 1; i <= n; ++i) {
while (q.size() && q.front().second < i - k) {
q.pop_front();
}
f[i] = q.front().first + sum[i] + stoi[i];
double d = f[i] + stoi[i + 1] - sum[i + 1];
while (q.size() && q.back().first >= d) q.pop_back();
if (i < n) q.push_back({ d, i});
}
cout << fixed << setprecision(12) << f[n];
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
while (T --) {
solve();
}
return 0;
}