D - Long Waiting
题意:
餐厅最多同时容纳K人
单队列管理,先进先出
N组顾客按顺序到达,每组有:到达时间Aᵢ、人数Cᵢ、用餐时间Bᵢ
进入条件:
在队首位置
餐厅现有人数 + 该组人数 ≤ K
需要计算每组实际进入餐厅的时间
思路:
考虑使用优先队列(最小堆)按离开时间排序
对于每一组,分类讨论,若当前空间可以容纳该组,直接入队,该组答案为上一组入队时间和该组可进入时间的最大值。
否则,不断弹出队头元素,直到当前组可以进入,该组答案为max(该组到达时间, 最后弹出组的离开时间)
代码
#include<bits/stdc++.h>
#define ll long long
#define ce cerr
#define ull unsigned long long
#define lll __int128
using namespace std;
#define int long long
const int inf = 0x3f3f3f3f;
const ll iinf = 1e18;
const int N = 3e5 + 10;
//cin.ignore(std::numeric_limits< streamsize >::max(), '\n');
int t;struct node {int x, y, z, w;
};
struct cmp {bool operator () (const node & a, const node & b) const {return a.y > b.y;}
};
void solve() {int n, k;cin >> n >> k;vector<node> vec (n + 1);vector<int> res (n + 1);priority_queue<node, vector<node>, cmp> que;for (int i = 1; i <= n; ++i) {int x, y, z;cin >> x >> y >> z;vec[i] = {x, x + y, z, y};}int now = 0;for (int i = 1; i <= n; ++i) {if (now + vec[i].z <= k) {now += vec[i].z;res[i] = max (res[i - 1], vec[i].x);que.push ({res[i], res[i] + vec[i].w, vec[i].z, vec[i].w});}else{node it;while (!que.empty () && now + vec[i].z > k) {it = que.top ();que.pop ();now -= it.z;}res[i] = max (vec[i].x, it.w + it.x);que.push ({res[i], res[i] + vec[i].w, vec[i].z, vec[i].w});now += vec[i].z;}}for (int i = 1; i <= n; ++i) {cout << res[i] << "\n";}
}
signed main() {ios::sync_with_stdio (false);cin.tie(NULL);cout.tie(NULL);t = 1;//cin >> t;while (t --) {solve();}return 0;
}
E - Sum of Subarrays
题意:
给定一个长度为 \(N\) 的整数序列 \(A = (A_1, A_2, \ldots, A_N)\),以及 \(Q\) 个查询。每个查询给出两个整数 \(L_i\) 和 \(R_i\),要求计算:
即,对于查询区间 \([L_i, R_i]\),计算所有连续子数组 \([l, r]\)(满足 \(L_i \le l \le r \le R_i\))的和之和。
若 \(A = [1, 2, 3]\),查询 \(L = 1, R = 3\),则需计算以下子数组的和并相加:
- \([1,1]\)、\([1,2]\)、\([1,3]\)
- \([2,2]\)、\([2,3]\)
- \([3,3]\)
思路:
1. 数学变换
原问题中的三重求和可以转化为对每个元素 \(A_j\) 的贡献计算。对于每个 \(j\)(在区间 \([L, R]\) 内),它被包含在那些满足 \(l \leq j \leq r\) 且 \(L \leq l \leq r \leq R\) 的子数组 \([l, r]\) 中。
这样的子数组个数为:
因此,原式等价于:
2. 展开乘积
将 \((j - L + 1) \times (R - j + 1)\) 展开:
对于这个式子,用前缀和优化即可
代码
#include<bits/stdc++.h>
#define ll long long
#define ce cerr
#define ull unsigned long long
#define lll __int128
using namespace std;
#define int long long
const int inf = 0x3f3f3f3f;
const ll iinf = 1e18;//cin.ignore(std::numeric_limits< streamsize >::max(), '\n');
int t;void solve() {int n, q;cin >> n >> q;vector<ll> a (n + 1);vector<ll> iai (n + 1);vector<ll> iiai (n + 1);vector<ll> ai (n + 1);for (int i = 1; i <= n; ++i) {cin >> a[i];ll temp = i * a[i];iai[i] = temp + iai[i - 1];temp = temp * i;iiai[i] = iiai[i - 1] + temp;ai[i] = ai[i - 1] + a[i];}while (q --) {int l, r;cin >> l >> r;ll len = r - l + 1;ll one = (iai[r] - iai[l - 1]) * (len + 2 * l - 1);ll two = iiai[r] - iiai[l - 1];ll three = (l - l * l + len - l * len) * (ai[r] - ai[l - 1]);cout << one - two + three << "\n";}
}
signed main() {ios::sync_with_stdio (false);cin.tie(NULL);cout.tie(NULL);t = 1;//cin >> t;while (t --) {solve();}return 0;
}
F - Loud Cicada
题意:
给定 n 个正整数 a[1..n],求在 1 到 y 之间,有多少个数 x,使得 x 能被 a[1..n] 中至少 m 个数整除。
思路:
考虑容斥原理:
枚举所有非空子集:遍历所有可能的子集(从 1 到 (1<<n)-1),表示从 n 个数中选取的子集。
计算子集的贡献:
对于每个子集,计算子集中元素的个数 cnt 和最小公倍数 Lcm。
如果 Lcm > y,则该子集没有贡献(因为 y/Lcm = 0)。
如果 cnt < m,则跳过(因为我们需要至少 m 个元素)。
如果 cnt >= m,则计算该子集的贡献:y / Lcm * C[cnt][m]。
容斥原理应用:
如果 (cnt - m) 是奇数,则减去该贡献:res -= y / Lcm * C[cnt][m]
如果 (cnt - m) 是偶数,则加上该贡献:res += y / Lcm * C[cnt][m]
代码
#include<bits/stdc++.h>
#define ll long long
#define ce cerr
#define ull unsigned long long
#define lll __int128
#define PII pair<int, int>
#define PLL pair<long ,long>using namespace std;const int inf = 0x3f3f3f3f;
const ll iinf = 1e18;//cin.ignore(std::numeric_limits< streamsize >::max(), '\n');
int t;
static int C[21][21];void init () {for (int i = 0; i <= 20; ++i) {C[i][0] = C[i][i] = 1;for (int j = 1; j < i; ++j) {C[i][j] = C[i - 1][j - 1] + C[i - 1][j];}}
}lll gcd (lll a, lll b) {return b ? gcd (b, a % b) : a;
}
lll lcm (lll a, lll b) {return a * b / gcd (a, b);
}
void solve() {init ();ll n, m, y;cin >> n >> m >> y;vector<ll> a (n + 1);for (int i = 1; i <= n; ++i) {cin >> a[i];}ll res = 0;for (int k = 1; k < (1 << n); ++k) {int temp = k;int cnt = 0;ll Gcd = 0;lll mul = 1;lll Lcm = 1;bool flag = false;for (int i = 0; i < n; ++i) { if ((temp >> i) & 1) {Lcm = lcm (Lcm, a[i + 1]);if (Lcm > y) {flag = 1;break;}mul = mul * a[i + 1];cnt ++;}}if (flag) continue;if (cnt < m) {continue;}else{if ((cnt - m) & 1) {res += -1 * y / Lcm * C[cnt][m];}else{res += y / Lcm * C[cnt][m];}}}cout << res << "\n";
}
int main() {ios::sync_with_stdio (false);cin.tie(NULL);cout.tie(NULL);t = 1;//cin >> t;while (t --) {solve();}return 0;
}