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 好像不太一样
\[\sum\limits_{i=1}^n\sum\limits_{j=1}^n a_ia_j\lfloor \frac{x\gcd(a_i,a_j)+y}{z}\rfloor \]当 \(\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\) ,式子转化成
\[\sum\limits_{i=1}^n\sum\limits_{j=1}^n d^2 \times \frac{a_i}{d}\frac{a_j}{d}\times p \]\[d^2 \times p\times \sum\limits_{d|a_i} \frac{a_i}{d} \sum\limits_{d|a_j} \frac{a_j}{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\) 时,答案为
\[\sum\limits_{h_i<k} h_i-(a_i-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;
}
标签:int,题解,ll,华中农业大学,cin,++,第十三届,sum,size
From: https://www.cnblogs.com/martian148/p/18134727