A - scx 的散文詩句
Solution
正負分開來分別處理,按照絕對值從大到小排序,兩兩匹配
注意:當沒有 \(0\) 且 正數 和 負數 都為奇數,即最後剩下一個正數一個負數時,必須匹配
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve() {
int n; cin >> n;
vector<ll> a, b;
int cnt_0 = 0;
for (int i = 1; i <= n; i++) {
ll x; cin >> x;
if (x > 0) a.push_back(x);
if (x < 0) b.push_back(x);
if (x == 0) cnt_0 ++;
}
ll ans = 0;
sort(a.begin(), a.end());
reverse(a.begin(), a.end());
sort(b.begin(), b.end());
for (int i = 0; i < a.size(); i += 2) {
if (i + 1 < a.size())
ans += a[i] * a[i + 1];
}
for (int i = 0; i < b.size(); i += 2) {
if (i + 1 < b.size())
ans += b[i] * b[i + 1];
}
if (cnt_0 == 0 && a.size() % 2 == 1 && b.size() % 2 == 1)
ans += a.back() * b.back();
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int t; cin >> t;
while (t--) solve();
}
B - 喵喵喵
Solution
我的做法和 std 好像不太一樣
當 \(\gcd(a_i,a_j) =d\) 的值確定了之後,\(\lfloor \frac{x\gcd(a_i,a_j)+y}{z}\rfloor=p\) 的值也就確定了
關鍵是 \(a_ia_j\),考慮把 \(a_ia_j\) 變成 \(d^2 \times \frac{a_i}{d}\frac{a_j}{d}\)
我們列舉一個 \(d\) ,式子轉化成
這個式子可以使用調和做法求出
但是有可能會算出,比如 \(8,4\) 會在 \(2\) 的地方算一次答案,會在 \(4\) 的地方算一個答案
所以我們對於 \(d\),需要在 \(d\) 的倍數的地方把此時 \(d\) 的貢獻減去
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll TT = 1e9 + 7;
ll x, y, z;
ll read() {
ll ret = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch <= '9' && ch >= '0') ret = ret * 10 + ch - '0', ch = getchar();
return ret;
}
void print(ll x) {
if (x == 0) return ;
print(x / 10);
putchar(x % 10 + '0');
}
int main() {
int n; cin >> n;
ll ans = 0;
x = read(), y = read(), z = read();
vector<ll> a(n + 1);
for (int i = 1; i <= n; i++)
a[i] = read();
ll max_x = *max_element(a.begin() + 1, a.end());
vector<ll> cnt(max_x + 1, 0), p(max_x + 1, 0);
for (int i = 1; i <= n; i++)
p[a[i]]++;
for (ll d = max_x; d >= 1; d --) {
ll now = 0, os = (x * d + y) / z;
ll pre = 0;
for (int j = 1; j * d <= max_x; j++) {
pre = (pre + p[j * d] * j) % TT;
}
for (int j = 1; j * d <= max_x; j++) {
now = (now + pre * p[j * d] % TT * j) % TT;
}
ll oa = d * d % TT;
now = oa * now % TT;
cnt[d] = now;
for (int j = 2; j * d <= max_x; j++)
cnt[d] = ((cnt[d] - cnt[j * d]) % TT + TT) % TT;
ans = (ans + cnt[d] * os) % TT;
}
print(ans);
return 0;
}
C - 貓貓大隊
Solution
把人類看作 \(0\),貓貓狀態看作 \(1\)
使用魔法就可以看成異或操作
Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int op = 0;
int n; cin >> n;
for (int i = 1; i <= n; i++) {
int now; cin >> now;
op ^= now;
}
if (op == 0)
cout << "zzy" << endl;
else
cout << "miao" << endl;
return 0;
}
D - 無限的韻律源點
Solution
total best 的維護非常簡單,用一個小根堆維護即可
recent best 的維護較複雜,可以使用 set + 一個大根堆維護 \([i - ra + 1, i]\) 的前 \(rb\) 大值
具體地,先從 \(set\) 中刪去不合法元素,再把 \(a[i]\) 插入大根堆中,再對 set 的最小值和大根堆的對頂進行交換
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pil;
const ll MAXN = 2e5+5;
ll n, b, ra, rb, a[MAXN], flag[MAXN], ans;
int main(){
ios::sync_with_stdio(false);
cin >> n >> b >> ra >> rb;
for(int i = 1; i <= n; i ++){
cin >> a[i];
}
priority_queue<ll, vector<ll>, greater<ll> > total;
set<pil> st;
priority_queue<pil> op;
ll sum1 = 0, sum2 = 0;
for(int i = 1; i <= n; i ++){
if(total.size() < b || total.top() <= a[i]){
sum1 += a[i];
total.push(a[i]);
}
while(total.size() > b){
sum1 -= total.top();
total.pop();
}
op.push({a[i], i});
for(int i = 1; i <= n; i ++){
}
while(!op.empty() && op.top().second <= max(0ll, i - ra))
op.pop();
if(flag[max(0ll, i - ra)]){
st.erase({a[max(0ll, i - ra)], max(0ll, i - ra)});
flag[max(0ll, i - ra)] = 0;
sum2 -= a[max(0ll, i - ra)];
}
if(st.size() < rb || st.begin() -> first <= op.top().first){
st.insert(op.top());
sum2 += op.top().first;
flag[op.top().second] = 1;
op.pop();
}
while(st.size() > rb){
sum2 -= st.begin() -> first;
flag[st.begin() -> second] = 0;
op.push(*st.begin());
st.erase(st.begin());
}
ans = max(ans, sum1 + sum2);
}
cout << ans << endl;
return 0;
}
E - 怯戰蜥蜴
Solution
求字首和,在字首和上二分
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 2e5+5;
ll n, q, a[MAXN], s[MAXN], x;
int main(){
ios::sync_with_stdio(false);
cin >> n >> q;
for(int i = 1; i <= n; i ++){
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
while(q --){
cin >> x;
ll idx = upper_bound(s + 1, s + n + 1, x) - s;
cout << idx - 1 << endl;
}
return 0;
}
H - To the Moon, Finding Paradise
Solution
考慮使用傳送器不會造成能量損失,能量 \(w\) 越大,可走的邊越多,\(s-t\) 的體力消耗值越小,滿足單調性
二分答案能量 \(w\),check 使用 \(BFS\) 檢視 \(s-t\) 的最小值,若小於 \(c\) 則 check 成功
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const ll inf = 1e18;
int main() {
int N, M, S, T, C; cin >> N >> M >> S >> T >> C;
vector<ll> V(N + 1, 0);
for (int i = 1; i <= N; i++) cin >> V[i];
vector<vector<pii> > g(N + 1, vector<pii>());
for (int i = 1; i <= M; i++) {
int u, v, w; cin >> u >> v >> w;
g[u].push_back({v, w});
}
auto check = [&] (int W) {
vector<ll> dis(N + 1, inf);
priority_queue<pii, vector<pii>, greater<pii> > pq;
pq.push({V[S], S}); dis[S] = V[S];
while (!pq.empty()) {
auto [d, u] = pq.top(); pq.pop();
if (d != dis[u]) continue;
for (auto [v, w] : g[u]) {
if (w > W) continue;
if (dis[v] > d + V[v]) {
dis[v] = d + V[v];
pq.push({dis[v], v});
}
}
}
return dis[T] <= C;
};
int l = -1, r = 1e9;
while (l + 1 < r) {
int mid = l + r >> 1;
if (check (mid)) r = mid;
else l = mid;
}
cout << r << endl;
return 0;
}
I - fumo 星
Solution
列舉兩個點生成一條直線
最後把所有直線排序後去重即可
Code
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
const int inf = 0x3f3f3f3f;
int cmp (double A, double B) {
if (fabs(A - B) < eps) return 0;
if (A < B) return -1;
else return 1;
}
struct Node {
double x, y;
Node() {x = 0; y = 0;}
bool operator <(const Node B) const {
return x < B.x || (x == B.x && y < B.y);
}
};
struct Line {
double k, b;
Line() {k = 0; b = 0;}
Line(Node A, Node B) {
if (A.x == B.x) {
k = inf; b = A.x;
}
else {
k = (A.y - B.y) / (A.x - B.x);
b = A.y - k * A.x;
}
}
bool operator <(const Line B) const {
return k < B.k || (k == B.k && b < B.b);
}
};
int main() {
int n; cin >> n;
vector<Node> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i].x >> a[i].y;
}
sort (a.begin(), a.end());
for (int i = 1; i < n; i++) {
if (cmp(a[i].x, a[i - 1].x) == 0 && cmp (a[i].y, a[i - 1].y) == 0) {
cout << "inf" << endl;
return 0;
}
}
vector<Line> p;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++) {
p.push_back(Line(a[i], a[j]));
}
int cnt = 0;
sort (p.begin(), p.end());
for (int i = 1; i < p.size(); i++) {
if (cmp(p[i].k, p[i - 1].k) == 0 && cmp(p[i].b, p[i - 1].b) == 0)
cnt ++;
}
cout << p.size() - cnt << endl;
return 0;
}
J - 上春山
Solution
當高度為 \(k\) 時,答案為
按照 \(h_i\) 從大到小排序後,\(\sum h_i\) 和 \(\sum a_i\) 可以求出來,\(\sum k=k\times j\) 其中 \(j\) 表示 \(h_i\) 比 \(k\) 大的個數
由於每部分都說獨立的,所以 \(k\) 越大越好,也就是取當前最矮的 \(h_i -1\)
就這樣列舉找出最大值即可
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Node {
ll h, a;
bool operator < (const Node B) const {
return h > B.h || (h == B.h && a < B.a);
}
};
ll ans = 0;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n;cin >> n;
vector<Node> p(n);
for (int i = 0; i < n; i++)
cin >> p[i].h;
for (int i = 0; i < n; i++)
cin >> p[i].a;
sort(p.begin(), p.end());
ll sum_h = 0, sum_a = 0;
for (int i = 0; i < n;) {
int j = i;
while (j < n && p[j].h == p[i].h) {
sum_h += p[j].h;
sum_a += p[j].a;
j++;
}
ll k = p[i].h - 1;
ll now = sum_a - sum_h + k * j;
ans = max (ans, now);
i = j;
}
cout << ans << endl;
return 0;
}
L - 南湖少年團
Solution
直接使用 substr 截下來字串即可
Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
string s1, s2; cin >> s1 >> s2;
int ans = 0;
for (int i = 0; i + s1.size() - 1 < s2.size(); i++) {
if (s2.substr(i, s1.size()) == s1)
ans ++;
}
cout << ans << endl;
return 0;
}
M - 上帝造題的八分鐘
Solution
數位 DP 板子題
定義 \(dp[pos][cp][pre1][pre2][limit][lead]\)
表示列舉到 \(pos\) 位置,差值位 \(cp\),前一個位置為 \(pre1\),前兩個位置為 \(pre2\),最大限制和前導零限制
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll TT = 1e9 + 7;
ll dp[104][205][11][11][2][2][2];
ll dfs(int pos, int cp, int pre1, int pre2, int limit, int n3, int lead, vector<int> &num) {
ll ret = 0;
if (pos == -1)
return n3 && (abs (cp - 100) >= 1);
if (~ dp[pos][cp][pre1][pre2][limit][n3][lead])
return dp[pos][cp][pre1][pre2][limit][n3][lead];
int up = (limit ? num[pos] : 9);
for (int i = 0; i <= up; i++) {
if (lead && i == 0)
ret += dfs (pos - 1, cp, i, pre1, limit && (i == up), n3 , 1, num);
else
ret += dfs (pos - 1, cp + (i == 0) - (i == 1), i, pre1, limit && (i == up), n3 | (i == 3 && pre1 == 3 && pre2 == 3), 0, num);
ret %= TT;
}
return dp[pos][cp][pre1][pre2][limit][n3][lead] = ret;
}
ll solve(vector<int> p) {
memset(dp, -1, sizeof dp);
return dfs (p.size() - 1, 100, -1, -1, 1, 0, 1, p);
}
int check (string s) {
int op = 0, op2 = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '1') op ++;
if (s[i] == '0') op --;
}
for (int i = 0; i + 3 - 1 < s.size(); i++) {
if (s.substr(i, 3) == (string)"333")
op2 |= 1;
}
op = (abs (op) >= 1);
return op && op2;
}
int main() {
string l, r; cin >> l >> r;
vector<int> L, R;
for (int i = 0; i < l.size(); i++)
L.push_back(l[i] - '0');
for (int i = 0; i < r.size(); i++)
R.push_back(r[i] - '0');
reverse(R.begin(), R.end());
reverse(L.begin(), L.end());
ll ans = ((solve(R) - solve(L) + check(l)) % TT + TT) % TT;
cout << ans << endl;
return 0;
}