CSPS模拟8
怎么说呢,也许是在 7 里说的话成了成真?好像这把没什么太唐的地方。
唯一要说的是垃圾机子,本地跑 \(8.3s\) 交上去只跑了 \(1.7s\)?
害我卡 \(40min\) 常数还怀疑会不会有更优解而我写错了……
还有学长改的题目背景,相当有趣了。
T1酒吧 原题
场上躺了 \(1h\) 想 \(O(n \log n)\) 做法,放弃后写出 \(O(n)\) 做法,数据范围太过具有欺骗性。 建议卡掉暴力卡时过的,加强到1e7,这样别人才知道你写的是On。
其实还好,稍微注意便可以写出式子
暴力 \(O(n^2)\) 肯定不行,考虑优化然后想 1h nlog 没想出来。注意到 (其实是猜的) 转移具有一定的单调性,可以用单调栈维护最佳转移点,扫一遍出结果,复杂度 \(O(n)\)。
顺带一提结束后学长说要卡掉错解把自己的解搭进去了,最后的结果是 100 -> 99 -> 100,末了我还是对的。
码:
点击查看代码
#include <bits/extc++.h>
#define int long long
#define e_ putchar_unlocked(' ')
#define en_ putchar_unlocked('\n')
using namespace std;
inline int in() {
int n = 0; char p = getchar_unlocked();
while (p < '-') p = getchar_unlocked();
// bool f = p == '-' ? p = getchar_unlocked() : 0;
do n = (n<<1) + (n<<3) + (p ^ 48), p = getchar_unlocked();
while (isdigit(p));
// return f ? -n : n;
return n;
}
inline void in(int &n) { n = in();}
inline void out(int x) {
// if(x < 0) putchar_unlocked('-'), x = -x;
if(x >= 10) out(x/10);
putchar_unlocked(x % 10 + '0');
}
const int N = 5e5 + 10;
int p[N], n, f[N];
int q[N], l, r, ans;
signed main() {
freopen("bar.in", "r", stdin);
freopen("bar.out", "w", stdout);
in(n);
for(int i = 1; i <= n; i ++) {
in(p[i]);
}
f[1] = (n - 1) * p[1];
q[r = 1] = 1;
for(int i = 2; i <= n; i ++) {
while(1 < r and p[i] * (n - q[r]) - p[q[r]] * (n - i) + f[q[r]]
< p[i] * (n - q[r - 1]) - p[q[r - 1]] * (n - i) + f[q[r - 1]]) r --;
f[i] = (i - q[r]) * p[i] + (n - i) * (p[i] - p[q[r]]) + f[q[r]];
q[++ r] = i;
ans = max(f[i], ans);
}
out(ans);
return 0;
}
//1437964920328
//173771520824432
T2逆转 原题
题目背景基本确定是玩院审玩的
不得不吐槽 oj 评测机和我们用的电脑的惊人差距 我写的 \(O(n\log V \log n)\)。大样例跑了 \(13.7s\) 各种卡常最终优化到 \(8.3s\),结果交上去最慢的点就只跑了 \(1.7s\) 不知道是我写得太假还是数据不如样例……
注意到可以二分答案,于是二分答案 (废话) ,我的 check 写的比较抽象,又丑又长又慢,建议看别人的,所以不讲了(懒)。
码:
点击查看代码
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#include <bits/extc++.h>
#define int long long
#define e_ putchar_unlocked(' ')
#define en_ putchar_unlocked('\n')
using namespace std;
inline int in() {
int n = 0; char p = getchar_unlocked();
while (p < '-') p = getchar_unlocked();
// bool f = p == '-' ? p = getchar_unlocked() : 0;
do n = (n<<1) + (n<<3) + (p ^ 48), p = getchar_unlocked();
while (isdigit(p));
// return f ? -n : n;
return n;
}
template <typename T> inline void in(T &n) { n = in();}
inline void out(int x) {
// if(x < 0) putchar_unlocked('-'), x = -x;
if(x >= 10) out(x/10);
putchar_unlocked(x % 10 + '0');
}
const int N = 3e5 + 10;
int n, k, m;
int a[N], cnt;
#define t1 y_1
#define t2 y_2
typedef pair<int,int> pii;
bool vs1[N], vs2[N];
priority_queue<pii, vector<pii>, greater<pii> > t1,t2,T1,T2;
inline bool check(int lim) {
priority_queue<pii> q1 ,q2;
t1 = T1, t2 = T2;
for(int i = 1; i <= n; i ++)
vs1[i] = vs2[i] = 0;
int cnt = 0, s1 = 0, s2 = 0;
while(!t1.empty() and s1 + t1.top().first <= lim) {
s1 += t1.top().first;
cnt ++;
vs1[t1.top().second] = 1;
q1.push(t1.top());
t1.pop();
}
while(!t2.empty() and s2 + t2.top().first <= lim) {
s2 += t2.top().first;
cnt ++;
vs2[t2.top().second] = 1;
q2.push(t2.top());
t2.pop();
}
if(cnt >= k) return 1;
int l = m + 1, r = m, cc = cnt;
int S1 = s1, S2 = s2;
while(l <= n) {
if(vs2[l]) {
S2 -= a[l];
cc --;
while(!t2.empty() and t2.top().second <= l) t2.pop();
while(!t2.empty() and t2.top().first + S2 <= lim) S2 += t2.top().first, vs2[t2.top().second] = 1, t2.pop(), cc ++;
}
if(a[l] + S1 <= lim) {
q1.push({a[l],l});
S1 += a[l];
cc ++;
}
else if(!q1.empty() and a[l] < q1.top().first) {
S1 -= q1.top().first;
q1.pop();
S1 += a[l];
q1.push({a[l],l});
}
l++;
if(cc >= k) return 1;
}
cc = cnt;
S1 = s1, S2 =s2;
while(r >= 1) {
if(vs1[r]) {
S1 -= a[r];
cc --;
while(!t1.empty() and t1.top().second >= r) t1.pop();
while(!t1.empty() and S1 + t1.top().first <= lim) S1 += t1.top().first, vs1[t1.top().second] = 1, t1.pop(), cc ++;
}
if(a[r] + S2 <= lim) {
cc++;
q2.push({a[r], r});
S2 += a[r];
}
else {
if(!q2.empty() and q2.top().first > a[r]) {
S2 -= q2.top().first;
q2.pop();
S2 += a[r];
q2.push({a[r],r});
}
}
r--;
if(cc >= k) return 1;
}
return 0;
}
struct node {
int val, id;
} A[N], B[N];
signed main() {
freopen("ace.in", "r", stdin);
freopen("ace.out", "w", stdout);
in(n), in(k);
int l = 0;
for(int i = 1; i <= n; i ++) in(a[i]);
for(int i = 1; i <= n; i ++) A[i].val = a[i], A[i].id = i;//贪心缩小上下界
sort(A+1, A+1+n, [](node a, node b) { return a.val < b.val;});
int ans = 0, sum = 0, o = LONG_LONG_MAX;
for(int i = 1; i <= k / 2; i ++) {
l += A[i].val;
}
for(int i = 1; i <= k; i ++) {
B[i] = A[i];
sum += A[i].val;
}
sort(B + 1, B + 1 + k, [](node a, node b) { return a.id < b.id;});
for(int i = 1; i <= k; i ++) {
ans += B[i].val;
o = min(o, max(ans, sum - ans));
}
int r = o, mid;
m = (n + 1)/ 2;
for(int i = 1; i <= m; i ++) {
T1.push({a[i], i});
}
for(int i = m + 1; i <= n; i ++) {
T2.push({a[i], i});
}
while(l <= r) {
mid = (l + r) >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
out(l);
return 0;
}
这里是我调的别人的代码,怕他看不懂所以写了一些注释,放这里当做是解析的代餐了。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define Blue_Archive return 0
#define ent putchar_unlocked('\n')
#define con putchar_unlocked(' ')
using namespace std;
const int N = 3e5 + 7;
const int INF = 1e18;
int n;
int k;
int ans;
int a[N];
bool vis1[N];
bool vis2[N];
struct miku
{
int id;
int val;
}b[N];
// map<int,int> mp;
inline int read()
{
int k = 0,f = 1;
char c = getchar_unlocked();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar_unlocked();
}
while(c >= '0' && c <= '9') k = (k << 3) + (k << 1) + c - '0',c = getchar_unlocked();
return k * f;
}
inline void write(int x)
{
if(x < 0) putchar_unlocked('-'),x = -x;
if(x > 9) write(x / 10);
putchar_unlocked(x % 10 + '0');
}
inline bool check(int op)
{
priority_queue<pair<int, int>,vector<pair<int, int>>,greater<pair<int, int> > > t1,t2;
//? 记录最小的(在某一范围内,而不是现有的)以及下标(方便处理)
priority_queue<pair<int, int> > q1, q2;
memset(vis1, 0, sizeof vis1); // 两个要分开记录,不然分不清谁挤谁
memset(vis2, 0, sizeof vis2);
int m = n / 2;// mid 初始从哪里分割并没有影响,关键是后面的互挤,脑瘫就设 n/2 了(码还多一倍)
int cnt1 = 0, cnt2 = 0, sum1 = 0, sum2 = 0;
for(int i = 1; i <= m; i ++)// 处理第一段
{
if(sum1 + a[i] <= op) // 合理扩展
{
q1.push({a[i], i});
cnt1 ++;
sum1 += a[i];
vis1[i] = 1;
}
else
{
if(!q1.empty() && a[i] < q1.top().first)
{// 挤兑自己
sum1 -= q1.top().first;
vis1[q1.top().second] = 0;
// vis1[mp[q1.top()]] = 0;
// 用 map 假的, 同一个值出现多遍
q1.pop();
q1.push({a[i], i});
sum1 += a[i];
vis1[i] = 1;
}
}
}
for(int i = m + 1; i <= n; i ++)// 处理第二段
{
if(sum2 + a[i] <= op)
{
q2.push({a[i], i});
cnt2 ++;
sum2 += a[i];
vis2[i] = 1;
}
else
{
if(!q2.empty() && a[i] < q2.top().first)
{
sum2 -= q2.top().first;
vis2[q2.top().second] = 0;
q2.pop();
q2.push({a[i], i});
sum2 += a[i];
vis2[i] = 1;
}
}
}
for(int i = 1; i <= m; i ++) if(!vis1[i]) t1.push({a[i],i});
for(int i = m + 1; i <= n; i ++) if(!vis2[i]) t2.push({a[i],i});
if(cnt1 + cnt2 >= k) return 1;
int ct1 = cnt1, ct2 = cnt2, Sum1 = sum1, Sum2 = sum2;
for(int i = m + 1; i <= n; i ++) // 相当于是和上面接上
{
if(vis2[i])
{ // 被挤掉了
Sum2 -= a[i];
ct2 --;
while(!t2.empty() and t2.top().second <= i) t2.pop(); //退掉不合法的
while(!t2.empty() and t2.top().first + Sum2 <= op) // 反悔,被挤的那边也有反悔权利
Sum2 += t2.top().first, vis2[t2.top().second] = 1, ct2 ++, t2.pop();
}
if(a[i] + Sum1 <= op)
{//顺理成章的扩展
q1.push({a[i], 0}); // wc 我不用角标了我存他干啥
Sum1 += a[i];
ct1 ++;
}
else if(!q1.empty() and a[i] < q1.top().first)
{ // 挤兑自己的东西
Sum1 -= q1.top().first;
q1.pop();
Sum1 += a[i];
q1.push({a[i], 0});
}
if(ct1 + ct2 >= k) return 1;
}
ct1 = cnt1, ct2 = cnt2;
Sum1 = sum1, Sum2 = sum2;
for(int i = m; i >= 1; i --)
{//这一坨同理
if(vis1[i])
{
Sum1 -= a[i];
ct1 --;
while(!t1.empty() and (t1.top().second >= i)) t1.pop();
while(!t1.empty() and t1.top().first + Sum1 <= op)
Sum1 += t1.top().first, vis1[t1.top().second] = 1, ct1 ++, t1.pop();
}
if(a[i] + Sum2 <= op)
{
q2.push({a[i], 0});
Sum2 += a[i];
ct2 ++;
}
else if(!q2.empty() and a[i] < q2.top().first)
{
Sum2 -= q2.top().first;
q2.pop();
Sum2 += a[i];
q2.push({a[i],0});
}
if(ct1 + ct2 >= k) return 1;
}
return 0;
}
signed main()
{
// freopen("ace4.in","r",stdin);
// freopen("1.out","w",stdout);
freopen("ace.in","r",stdin);
freopen("ace.out","w",stdout);
n = read();
k = read();
if(k == 0)
{
puts("0");
Blue_Archive;
}
for(int i = 1;i <= n;i ++) a[i] = read();
int l = 1,r = INF,mid;
while(l <= r)
{
mid = (l + r) >> 1;
if(check(mid)) ans = mid,r = mid - 1;
else l = mid + 1;
}
write(ans); ent;
// cout << check(18809);
Blue_Archive;
}
// 18809
// 15879
// 19032
// 45895981476633
// 45896088528286
// 45896047837541
// 57856210411974
// 57856577304906
// 57857509546635
// 27069938397689
// 22131381592473
// 45895974401323
// 45895981476633
T3不会,不说
T4染色
特别帅的一道题,据说是某个国赛模拟的 \(T1\)。
大体是在考一些问题向位运算的转换和 \(bitset\) (我义父) 的使用。
场上根本没看这题,后来听同学讲完才发觉这道题真帅吧。
除了我写的这个慢的要死的东西以外还有一种做法,我更想说说内个。
是一种合并处理的思想,先将树拍下来,分块并提前处理区间使复杂度更加正确。因为会炸空间,所以小区间暴力大区间合并,但是复杂度仍不太对,于是对块进行二次分块,使超大区间的复杂度更加正确。然后某倒开题大蛇就过了。
这种思路和线段树很像对吧,所以我们机房另一位大蛇使用线段树维护也过了这题(空间没炸!)。
虽然我喜欢那种写法但是我写的代码并不是那种写法,我讲的做法和我写的没有任何关系。(讲的还可能是错的)。至于我写的是来自学长的题解的说。
码:
点击查看代码
#pragma GCC optimize(3)
#pragma GCC optimize(2)
// 你妈的常数到底能不能放过我这一次
#include <bits/extc++.h>
#define int long long
#define e_ putchar_unlocked(' ')
#define en_ putchar_unlocked('\n')
using namespace std;
inline int in() {
int n = 0; char p = getchar_unlocked();
while (p < '-') p = getchar_unlocked();
// bool f = p == '-' ? p = getchar_unlocked() : 0;
do n = (n<<1) + (n<<3) + (p ^ 48), p = getchar_unlocked();
while (isdigit(p));
// return f ? -n : n;
return n;
}
inline void in(int &n) { n = in();}
inline void out(int x) {
// if(x < 0) putchar_unlocked('-'), x = -x;
if(x >= 10) out(x/10);
putchar_unlocked(x % 10 + '0');
}
const int N = 3e5 + 10, B = 500, W = 150;
int u[N], v[N], c[N], pt[N], n, q;
vector<int> e[N];
int fa[N], dep[N], sz[N], wc[N], top[N], dfn[N], ed[N], cntn;
inline void dfs(int u, int f) {
dep[u] = dep[f] + 1, fa[u] = f, sz[u] = 1;
for(int v : e[u])
if(v != f) {
dfs(v, u);
sz[u] += sz[v];
wc[u] = sz[wc[u]] > sz[v] ? wc[u] : v;
}
}
inline void dps(int u, int tp) {
top[u] = tp; dfn[u] = ++cntn;
if(wc[u]) dps(wc[u], tp);
for(int v : e[u])
if(v != fa[u] and v != wc[u])
dps(v, v);
ed[u] = cntn;
}
inline int lca(int u, int v) {
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
u = fa[top[u]];
}
return dep[u] > dep[v] ? v : u;
}
inline int dist(int u, int v) {
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
int col[N], ans, op[N], x[N], y[N], opt;
int a[N], id[N], stk[N], tp, typ[N * 3];
bitset<N> s[W + 10], now;
inline void dcs(int u, int f) {
if(u != 1) stk[++tp] = u, typ[tp] = 0;
if(id[u]) stk[++tp] = u, typ[tp] = 1;
for(int v : e[u])
if(v != f)
dcs(v ,u);
if(u != 1) stk[++tp] = u, typ[tp] = 0;
}
inline void drs() {
now.reset();
for(int i = 1; i <= tp; i ++) {
if(!typ[i]) now.flip(col[stk[i]]);
else s[id[stk[i]]] = now;
}
}
inline bool inr(int u, int v) {
return dfn[v] <= dfn[u] and dfn[u] <= ed[v];
}
inline bool check(int x, int u, int v) {
if(x == u || x == v) return 1;
return inr(u, x) ^ inr(v, x);
}
int cc = 0;
inline bitset<N> get(int x) {
vector<int> pt;
while(!id[x]) {
pt.push_back(x);
x = fa[x];
cc ++;
}
bitset<N> res = s[id[x]];
for(int i : pt) {
res.flip(col[i]);
}
return res;
}
inline void solve(int l, int r) {
drs();
map<int, int> upd;
for(int i = l; i <= r; i ++) {
int tx = x[i], ty = y[i];
if(opt == 1) { tx ^= ans, ty ^= ans;}
if(op[i] == 1) {
upd[v[tx]] = ty;
}
else {
bitset<N> b = get(tx) ^ get(ty);
int lf = lca(tx, ty);
for(auto p : upd) {
if(p.first != lf and (check(p.first, tx, lf) || check(p.first, ty, lf))) {
b.flip(col[p.first]);
b.flip(p.second);
}
}
if(b.count() == dist(tx, ty)) {
puts("Yes");
ans = i;
}
else {
puts("No");
}
}
}
for(auto p : upd) {
col[p.first] = p.second;
}
}
mt19937 rd(time(0));
signed main() {
freopen("paint.in", "r", stdin);
freopen("paint.out", "w", stdout);
in(n), in(q), in(opt);
for(int i = 1; i < n; i ++) {
in(u[i]), in(v[i]), in(c[i]);
e[u[i]].push_back(v[i]);
e[v[i]].push_back(u[i]);
}
dfs(1, 0);
dps(1, 1);
for(int i = 1; i < n; i ++) {
if(dep[u[i]] > dep[v[i]]) swap(u[i], v[i]);
col[v[i]] = c[i];
}
for(int i = 1; i <= q; i ++) {
in(op[i]), in(x[i]), in(y[i]);
}
for(int i = 1; i <= n; i ++) a[i] = i;
shuffle(a + 2, a + 1 + n, rd);
for(int i = 1; i <= W; i ++)
id[a[i]] = i;
dcs(1, 0);
for(int i = 1; i <= q; i += B) {
solve(i, min(q, i + B - 1));
}
}
//1437964920328
//173771520824432

浙公网安备 33010602011771号