Y
K
N
U
F

CSPS模拟8

怎么说呢,也许是在 7 里说的话成了成真?好像这把没什么太唐的地方。
唯一要说的是垃圾机子,本地跑 \(8.3s\) 交上去只跑了 \(1.7s\)
害我卡 \(40min\) 常数还怀疑会不会有更优解而我写错了……
还有学长改的题目背景,相当有趣了。

T1酒吧 原题

场上躺了 \(1h\)\(O(n \log n)\) 做法,放弃后写出 \(O(n)\) 做法,数据范围太过具有欺骗性。 建议卡掉暴力卡时过的,加强到1e7,这样别人才知道你写的是On

其实还好,稍微注意便可以写出式子

\[f_i = max_{j=1}^n {p_i \times (n-j) - p_j \times (n-i) + f_j} \]

暴力 \(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

posted @ 2025-08-01 20:49  樓影沫瞬_Hz17  阅读(22)  评论(0)    收藏  举报