B3666
单调栈
用维护一个单调递减的栈,栈中存储下标,每遍历一个位置就加入栈并把小于它的元素都弹出,再把ans异或一遍
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int N = 1e6 + 5;
int n;
int a[N];
stack<int> s;
int ans;
signed main(){
cin.tie(0);
ios::sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++){
while(s.size() && a[i] > a[s.top()]){
ans ^= s.top();
s.pop();
}
s.push(i);
ans ^= i;
cout << ans << endl;
}
return 0;
}
P1725
DP, 单调队列优化
假设为第
格的冰冻指数,
为跳到第
格所能获取的最大冰冻指数,那么状态转移方程为
再用单调队列优化
#include<bits/stdc++.h>
using namespace std;
const int N = 4e5 + 5;
int n, l, r;
int arr[N], dp[N];
deque<int> q;
signed main(){
cin >> n >> l >> r;
for(int i = 0; i <= n; i++) cin >> arr[i];
memset(dp, -0x3f, sizeof(dp));
dp[0] = 0;
for(int i = 0; i <= n + r - l; i++){
while(q.size() && i - q.front() > r - l) q.pop_front();
while(q.size() && dp[q.back()] <= dp[i]) q.pop_back();
q.push_back(i);
dp[i + l] = dp[q.front()] + arr[i + l];
}
int ans = -0x3f3f3f3f;
for(int i = n + 1; i <= n + r; i++) ans = max(ans, dp[i]);
cout << ans;
return 0;
}
P1439
单调队列+二分
把A中元素的位置记录下来,再依次输入B,每输入一个元素就二分查找A中对应的值,再找出最大值
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int a[N], b[N];
int n, x, rr;
int q[N], id[N];
int main(){
cin >> n;
memset(id, -1, sizeof id);
for(int i = 1; i <= n; i++){
cin >> x;
id[x] = i;
}
q[0] = -1;
for(int i = 1, x; i <= n; i++){
cin >> x;
int k = id[x];
if(k == -1) continue;
int r = lower_bound(q, q + rr, k) - q;
q[r] = k;
rr = max(rr, r + 1);
}
cout << rr;
return 0;
}
P1631
堆
把A和B从小到大排序,然后再相加得到个和,可以发现:
首先,将这N个队列中的第一个元素放入一个堆中,然后,每次取出堆中的最小值。若这个最小值来自于第k个队列,那么,就将第k个队列的下一个元素放入堆中。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], b[N];
priority_queue<int, vector<int>, greater<int> > q;
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) cin >> b[i];
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n && (i - 1) * (j - 1) <= n; j++){
q.push(a[i] + b[j]);
}
}
int cnt = 0;
while(q.size()){
cout << q.top() << " ";
q.pop();
cnt++;
if(cnt == n) break;
}
return 0;
}
P2949
反悔贪心
把数据储存在pair里,先按照时间排序,再按照利润排序,每次有更好的且时间满了的时候就将堆中最小的拿出来去掉,换上利润高的。
#include<bits/stdc++.h>
#define pii pair<int, int>
#define d first
#define p second
#define int long long
using namespace std;
const int N = 1e5 + 5;
int n;
pii w[N];
priority_queue<int, vector<int>, greater<int> > q;
int ans;
signed main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> w[i].d >> w[i].p;
sort(w + 1, w + 1 + n);
for(int i = 1; i <= n; i++){
if(w[i].d == q.size()){
if(w[i].p > q.top()){
ans -= q.top();
q.pop();
q.push(w[i].p);
ans += w[i].p;
}
}
else{
q.push(w[i].p);
ans += w[i].p;
}
}
cout << ans;
return 0;
}
P1717
贪心
枚举每个鱼塘,算出时间,选最好的那个
#include<bits/stdc++.h>
#define pii pair<int, int>
#define x first
#define y second
using namespace std;
const int N = 30;
int n, T, f[N], d[N], ne[N], ans;
signed main(){
cin >> n >> T;
for(int i = 1; i <= n; i++) cin >> f[i];
for(int i = 1; i <= n; i++) cin >> d[i];
for(int i = 1; i < n; i++) cin >> ne[i];
for(int i = 1; i <= n; i++){
priority_queue<pii> q;
int tt = T * 12;
for(int j = 1; j <= i; j++) q.push({f[j], d[j]});
for(int j = 1; j < i; j++) tt -= ne[j];
int res = 0;
while(tt > 0){
pii t = q.top();
res += t.x;
tt--;
if(t.x <= 0) break;
q.pop();
q.push({t.x - t.y, t.y});
}
ans = max(ans, res);
}
cout << ans;
return 0;
}
P4588
线段树
将数据按时间排序,建线段树,维护区间乘。这样的话根节点就是到现在为止的所有数的乘积。
第一个操作就是将当前时间的值设为m。
第二个操作就是将pos时的值置为1。
#include<bits/stdc++.h>
#define int long long
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
const int N = 1e5 + 5;
int op, T, n, m, M;
struct node{
int l, r, mul;
}tr[N << 2];
void pushup(int u){
tr[u].mul = (tr[ls].mul * tr[rs].mul) % M;
}
void build(int u, int l, int r){
tr[u] = {l, r, 1};
if(l == r) return;
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(u);
}
void update(int u, int pos,int c){
if(tr[u].l == tr[u].r && tr[u].l == pos){
tr[u].mul = c;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if(pos <= mid) update(ls, pos, c);
if(pos > mid) update(rs, pos, c);
pushup(u);
}
signed main(){
cin >> T;
while(T--){
cin >> n >> M;
memset(tr, 0, sizeof(tr));
build(1, 1, n);
for(int i = 1, x; i <= n; i++){
cin >> op >> x;
if(op == 1){
update(1, i, x);
}else{
update(1, x, 1);
}
cout << tr[1].mul << endl;
}
}
return 0;
}

4268

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



