2025-11-18 hetao1733837的刷题记录
灵茶八题 - 子数组 ^w+
原题链接:灵茶八题 - 子数组 ^w+
分析
位运算是独立的,即每一位互不影响,所以,考虑每一位的贡献。
所以题目 ∑ l = 1 n ∑ r = l n ( a l ⨁ a l + 1 ⨁ ⋅ ⋅ ⋅ ⨁ a r − 1 ⨁ a r ) \sum\limits_{l=1}^{n}\sum\limits_{r=l}^{n}(a_l\bigoplus a_{l+1}\bigoplus ···\bigoplus a_{r-1} \bigoplus a_r) l=1∑nr=l∑n(al⨁al+1⨁⋅⋅⋅⨁ar−1⨁ar)
转化为 ∑ k = 0 30 ( c n t 0 k × c n t 1 k ) × 2 k \sum\limits_{k=0}^{30}(cnt0_k\times cnt1_k)\times 2^k k=0∑30(cnt0k×cnt1k)×2k
正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int a[N], sum[N];
int n;
signed main(){
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
sum[i] = sum[i - 1] ^ a[i];
}
int ans = 0;
for (int bit = 0; bit < 31; bit++){
int cnt0 = 1, cnt1 = 0;
for (int i = 1; i <= n; i++){
if (sum[i] >> bit & 1){
cnt1++;
}
else{
cnt0++;
}
}
ans += cnt0 * cnt1 * (1 << bit);
}
cout << ans;
return 0;
}
幽默的世界。
原题链接:幽默的世界。
分析
思路正确!幽默序列即为前面都是非正数,最后一个是正数,和为正数,好的,继续……不会了?
那么,对于每个正数向前找非正数,且区间和为正数,若找到了 a a a个非正数,贡献为 a + 1 a+1 a+1,这一步预处理即可。
但是,如果询问区间将以正数为划分的区间劈开怎么办?那么最后一个是不会有贡献的,再处理左端点即可。
正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200005;
int n, q, a[N];
long long sum[N];
int l, r;
int pos[N], top;
int w[N];
int work(int k){
int l = 1, r = top;
while (l <= r){
int mid = (l + r) >> 1;
if (pos[mid] > k)
r = mid - 1;
else
l = mid + 1;
}
return r;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
int tot = 0;
int p;
for (int i = n; i; i--){
if (a[i] > 0){
p = i;
tot = 0;
pos[++top] = p;
}
tot += a[i];
if (tot > 0)
w[p]++;
}
sort(pos + 1, pos + top + 1);
for (int i = 1; i <= top; i++)
sum[i] = sum[i - 1] + w[pos[i]];
while (q--){
cin >> l >> r;
int ans = 0;
int L = work(l), R = work(r);
if (pos[R] < l)
goto O;
if (pos[L] < l)
++L;
ans = sum[R] - sum[L] + min(w[pos[L]], pos[L] - l + 1);
O:cout << ans << '\n';
}
}
[ABC203D] Pond
原题链接1:[ABC203D] Pond
原题链接2:D - Pond
分析
二分答案……嗯,我没看题。ber,单调性在哪?容我稍考。这能二分答案?咋的,二分中位数?确实如此,但是怎么 c h e c k check check?交给题解。
操,数据范围 N ≤ 800 N\le 800 N≤800,当成 N ≤ 1 0 5 N\le 10^5 N≤105了。
那么,就可以 O ( n 2 ) O(n^2) O(n2)check了。
写出来 j < = j j <= j j<=j这辈子也是有了。
正解
#include <bits/stdc++.h>
using namespace std;
const int N = 805;
int n, k, a[N][N];
bool check(int x){
int b[N][N], sum[N][N];
memset(b, 0, sizeof(b));
memset(sum, 0, sizeof(sum));
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
if (a[i][j] > x)
b[i][j] = 1;
else
b[i][j] = 0;
}
}
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + b[i][j];
}
}
for (int i = 1; i + k - 1 <= n; i++){
for (int j = 1; j + k - 1 <= n; j++){
int tmp = sum[i + k - 1][j + k - 1] - sum[i - 1][j + k - 1] - sum[i + k - 1][j - 1] + sum[i - 1][j - 1];
if (tmp < k * k / 2 + 1)
return true;
}
}
return false;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
int l = 0x3f3f3f3f, r = 0xc0c0c0c0;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
cin >> a[i][j];
l = min(l, a[i][j]);
r = max(r, a[i][j]);
}
}
int ans = r;
while (l <= r){
int mid = (l + r) >> 1;
if (check(mid)){
ans = mid;
r = mid - 1;
}
else{
l = mid + 1;
}
}
cout << ans;
return 0;
}
CF1260D A Game with Traps
原题链接1:CF1260D A Game with Traps
原题链接2:1260D
分析
本来以为是二分答案+背包check,转头一看 N , M ≤ 1 0 5 N,M\le 10^5 N,M≤105吓哭了。稍考一下。时间越长似乎越优,所以我们最好把时间尽量用完,所以尽量拆除陷阱。
猜想:二分求得的是士兵的个数,check的是时间,而我们把士兵按照敏捷度排序,先二分找到允许最不敏捷士兵通过的陷阱,”你“去拆掉即可?再返回,加上带着这些士兵到达 n + 1 n+1 n+1的时间?复杂度大概是两个 l o g log log?那二分答案在哪?
那不对啊,找到 d i d_i di之后没法确定最大的r啊,咋这么阴?
我要看题解!!!
哦,好像可以 O ( n ) O(n) O(n)求最大 r i r_i ri?我先he一下题解。
确实,我是糖糖, O ( k ) O(k) O(k)差分 c h e c k check check是允许的。
正解
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, m, k, t;
int a[N];
int cha[N];
struct node{
int l, r, d;
}inp[N];
bool check(int x){
int lowest = a[x];
memset(cha, 0, sizeof(cha));
for (int i = 1; i <= k; i++){
if (inp[i].d > lowest){
cha[inp[i].l]++;
cha[inp[i].r + 1]--;
}
}
int lst = 0, sum = 0;
for (int i = 1; i <= n + 1; i++){
cha[i] += cha[i - 1];
if (cha[i] != 0){
sum += 3;
}
else{
sum += 1;
}
}
if (sum <= t)
return true;
return false;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> m >> n >> k >> t;
for (int i = 1; i <= m; i++){
cin >> a[i];
}
for (int i = 1; i <= k; i++){
cin >> inp[i].l >> inp[i].r >> inp[i].d;
}
sort(a + 1, a + m + 1, greater<int>());
int l = 0, r = m + 1;
while (l < r){
int mid = (l + r) >> 1;
if (check(mid)){
l = mid + 1;
}
else{
r = mid;
}
}
cout << max(0, r - 1);
}
还在In queue!
标准时间12:10:13交的,12:16:32才过!!!
LG2949 [USACO09OPEN] Work Scheduling G
原题链接:[USACO09OPEN] Work Scheduling G
分析
呃,你猜我理解了吗?并非。
正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n;
struct node{
int d, p;
}a[N];
bool cmp(node x, node y){
return x.d < y.d;
}
priority_queue<int, vector<int>, greater<int>> q;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i].d >> a[i].p;
sort(a + 1, a + n + 1, cmp);
int ans = 0;
for (int i = 1; i <= n; i++){
if (a[i].d > q.size()){
ans += a[i].p;
q.push(a[i].p);
}
else if (!q.empty() && q.top() < a[i].p){
ans += a[i].p - q.top();
q.pop();
q.push(a[i].p);
}
}
cout << ans;
}
LG2107 小 Z 的 AK 计划
原题链接:小 Z 的 AK 计划
呃……依旧叹为观止……
正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n, m;
struct node{
int x, t;
}a[N];
bool cmp(node p, node q){
return p.x < q.x;
}
priority_queue<int> q;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++){
cin >> a[i].x >> a[i].t;
}
int ans = 0;
sort(a + 1, a + n + 1, cmp);
int sum = 0;
int cnt = 0;
for (int i = 1; i <= n; i++){
sum += a[i].x - a[i - 1].x;
q.push(a[i].t);
cnt++;
sum += a[i].t;
while (!q.empty() && sum > m){
cnt--;
sum -= q.top();
q.pop();
}
if (sum > m)
break;
ans = max(ans, cnt);
}
cout << ans;
}
LG3545 [POI 2012] HUR-Warehouse Store
原题链接:[POI 2012] HUR-Warehouse Store
分析
感觉反悔贪心更是一种玄学……非常类似正经贪心,只是决策稍微复杂一点?好……呃……
那么,本题其实就是尽可能满足每一位顾客,当每日进货量无法满足,取出大根堆堆顶,然后删删加加就没了?
正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 250005;
int a[N], b[N];
priority_queue<pair<int, int>> q;
bool vis[N];
int n;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
cin >> b[i];
int sum = 0, ans = 0;
for (int i = 1; i <= n; i++){
sum += a[i];
if (sum < b[i] && !q.empty() && q.top().first > b[i]){
vis[q.top().second] = 0;
sum += q.top().first;
q.pop();
ans--;
}
if (sum >= b[i]){
sum -= b[i];
q.push({b[i], i});
vis[i] = 1;
ans++;
}
}
cout << ans << '\n';
for (int i = 1; i <= n; i++)
if (vis[i])
cout << i << " ";
}
LG6187 [NOI Online #1 提高组] 最小环
原题链接:最小环
分析
呃,贪心部分会了,数论部分……嘻嘻
和一下题解。
正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200005;
int a[N], f[N];
int n, m, k;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + n + 1);
while(m--){
int ans = 0;
cin >> k;
if (k == 0 || n == 1){
for (int i = 1; i <= n; i++)
ans += a[i] * a[i];
cout << ans << '\n';
continue;
}
int g = __gcd(n, k);
int len = n / g;
if (f[len]){
cout << f[len] << '\n';
continue;
}
for (int i = 1; i <= n; i += len){
for (int j = 0; j < len - 2; j++)
ans += a[i + j] * a[i + j + 2];
ans += (a[i] * a[i + 1] + a[i + len - 1] * a[i + len - 2]);
}
f[len] = ans;
cout << ans << '\n';
}
}
LG5656 【模板】二元一次不定方程 (exgcd)
原题链接:exgcd
分析
板子,但不会……
正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
struct node{
int GCD, x, y;
};
node exgcd(int a, int b){
if (b == 0)
return (node){a, 1, 0};
node tmp = exgcd(b, a % b);
return (node){tmp.GCD, tmp.y, tmp.x - a / b * tmp.y};
}
int T, a, b, c;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> T;
while (T--){
cin >> a >> b >> c;
node tmp = exgcd(a, b);
if (c % tmp.GCD){
cout << -1 << '\n';
continue;
}
tmp.x *= c / tmp.GCD;
tmp.y *= c / tmp.GCD;
int dx = b / tmp.GCD, dy = a / tmp.GCD;
int minx = (tmp.x % dx + dx - 1) % dx + 1;
int miny = (tmp.y % dy + dy - 1) % dy + 1;
int maxx = (c - b * miny) / a;
int maxy = (c - a * minx) / b;
if (maxy > 0){
cout << (maxx - minx) / dx + 1 << " " << minx << " " << miny << " " << maxx << " " << maxy << '\n';
}
else{
cout << minx << " " << miny << '\n';
}
}
}
LG2613 【模板】有理数取余
原题链接:有理数取余
分析
为啥 l o n g long long l o n g long long能过?
正解
#include <bits/stdc++.h>
#define int long long
#define mod 19260817
using namespace std;
int a, b, x, y;
inline int read(){
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = (x * 10 + c - '0') % mod;
c = getchar();
}
return x * f;
}
void exgcd(int a, int b, int &x, int &y){
if (b == 0) {
x = 1;
y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= a / b * x;
}
signed main(){
a = read();
b = read();
if (b == 0){
cout << "Angry" << '\n';
return 0;
}
int x, y;
exgcd(b, mod, x, y);
x = (x % mod + mod) % mod;
cout << a * x % mod << '\n';
return 0;
}
1329

被折叠的 条评论
为什么被折叠?



