2025-11-18 hetao1733837的刷题记录

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=1nr=ln(alal+1⋅⋅⋅ar1ar)

转化为 ∑ 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=030(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 N800,当成 N ≤ 1 0 5 N\le 10^5 N105了。

那么,就可以 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,M105吓哭了。稍考一下。时间越长似乎越优,所以我们最好把时间尽量用完,所以尽量拆除陷阱。

猜想:二分求得的是士兵的个数,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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值