W
e
l
c
o
m
e
: )

[考试记录] 2024.11.22 noip模拟赛19

T1 镜的绮想 (mirror)

考虑维护中点 \(y\) 坐标数量,\(mid_y=(a_y+b_y)/2\),不过不用除。枚举所有相同 \(x\) 坐标点对即可。

#include<bits/stdc++.h>
using namespace std;
constexpr int N = 5e3 + 5, MX = 2e6 + 5;
int a[N<<1], pos[N<<1], cnt, ans, val[MX<<1];
struct node{ int x, y; }tn[N], fn[N];
vector<int> tvec[N<<1], fvec[N<<1];
int main(){
	freopen("mirror.in", "r", stdin); freopen("mirror.out", "w", stdout);
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n, m; cin>>n>>m; 
	for(int i=1; i<=n; ++i) cin>>tn[i].x>>tn[i].y, a[++cnt] = tn[i].x;
	for(int i=1; i<=m; ++i) cin>>fn[i].x>>fn[i].y, a[++cnt] = fn[i].x;
	sort(a+1, a+1+cnt); cnt = unique(a+1, a+1+cnt) - a - 1;
	for(int i=1; i<=n; ++i) tvec[lower_bound(a+1, a+1+cnt, tn[i].x)-a].emplace_back(tn[i].y);
	for(int i=1; i<=m; ++i) fvec[lower_bound(a+1, a+1+cnt, fn[i].x)-a].emplace_back(fn[i].y);
	for(int i=1; i<=cnt; ++i) if(!tvec[i].empty() && !fvec[i].empty())
		for(int tv : tvec[i]) for(int fv : fvec[i])
			++val[tv + fv + MX], ans = max(ans, val[tv + fv + MX]);
	return cout<<ans, 0;
}

T2 万物有灵 (animism)

不知道最大独立集是什么,然后就跳了,我有可能真的错过了 100pts

规律是简单的,我们称深度为 \(1\sim k\) 的树为基础树。那么最大独立集即为从树的最底层开始,取一层跳过一层以此类推。考虑利用一下周期性,当 \(k\) 为偶数的时候计算出基础树的奇数层的节点总数,和偶数层的节点总数,然后计算一下整棵树包含多少颗基础树。令 \(b_k\) 表示基础树的叶子数量,那么基础树的数量即为 \(1+b_k+b_k^2+b_k^3\dots\),等比数列求和即可。不过考虑到没有逆元的情况,可以使用矩阵乘法或者递归求解。对于 \(k\) 为奇数的情况,直接将 \(k*2\) 即可转化。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define it __int128
constexpr int N = 5e5 + 5;
int n, k, M, a[N<<1], b[N<<1];
inline int qpow(int a, int k){
	int res = 1; while(k){
		if(k & 1) res = (it)res * a % M;
		a = (it)a * a % M; k >>= 1;
	} return res;
}
inline int add(initializer_list<int> Add){
	int res = 0;
	for(int v : Add) res = res + v >= M ? res + v - M : res + v;
	return res;
}
inline int mul(initializer_list<int> Mul){
	int res = 1;
	for(int v : Mul) res = (it)res * v % M;
	return res;
}
inline void eg(int a, int b, int &x, int &y){
	if(!b) return x = 1, y = 0, void();
	eg(b, a%b, y, x); y -= a / b * x;
}
inline int inv(int k){
	int x = 0, y = 0; eg(k, M, x, y);
	x = ((x % M) + M) % M;
	if(x < 0) printf("fvv\n"), exit(0);
	return x;
}
signed main(){
	freopen("animism.in", "r", stdin); freopen("animism.out", "w", stdout);
	cin>>n>>k>>M;
	for(int i=1; i<=k; ++i) cin>>a[i];
	for(int i=k+1; i<=k<<1; ++i) a[i] = a[i-k];
	if(k & 1) k *= 2;
	b[1] = a[1]; int sum1 = a[1], sum2 = 0;
	for(int i=2; i<=k; ++i){
		b[i] = mul({b[i-1], a[i]});
		if(i & 1) sum1 = add({sum1, b[i]});
		else sum2 = add({sum2, b[i]});
	}
	if(!((n % k) & 1)){
		int res = 1, lst = qpow(b[k], n/k);
		int sum = mul({lst-1, inv(b[k]-1)});
		res = add({res, mul({sum, sum2})});
		for(int i=2; i<=n%k; i+=2)
			res = add({res, mul({b[i], lst})});
		cout<<abs(res); exit(0);
	} else {
		int res = 0, lst = qpow(b[k], n/k);
		int sum = mul({lst-1, inv(b[k]-1)});
		res = add({res, mul({sum, sum1})});
		for(int i=1; i<=n%k; i+=2)
			res = add({res, mul({b[i], lst})});
		cout<<abs(res); exit(0);
	}
}

T3 白石溪 (creek)

考场上苦思冥想如何优化 45pts dp 没想到是个贪心……

没太明白,颓过去的……

#include<bits/stdc++.h>
using namespace std;
constexpr int B = 1 << 15;
char buf[B], *p1 = buf, *p2 = buf;
#define gt() (p1==p2 && (p2=(p1=buf)+fread(buf, 1, B, stdin), p1==p2) ? EOF : *p1++)
template <typename T> inline void rd(T &x){
	x = 0; int f = 0; char ch = gt();
	for(; !isdigit(ch); ch = gt()) f ^= ch == '-';
	for(; isdigit(ch); ch = gt()) x = (x<<1) + (x<<3) + (ch^48);
	x = f ? -x : x;
}
template <typename T, typename ...TT> inline void rd(T &x, TT &...y){ rd(x), rd(y...); }
#define int long long
int p[1000005];
signed main(){
	freopen("creek.in", "r", stdin); freopen("creek.out", "w", stdout);
	int n, c, d; rd(n, c, d); int ans = 0, res = 0;
	for(int i=1, a, b; i<=n; ++i){
		rd(a, b); ans += a;
		p[i] = a - b - (i-1) * c - (n-i) * d;
	} sort(p+1, p+1+n); res = ans;
	for(int i=1; i<=n; ++i) ans -= p[i], res = max(res, ans - (c+d)*i*(i-1)/2);
	return printf("%lld", res), 0;
}

T4 上山岗 (uphill)

首先考虑构造出匹配数最多的方案,采用 田忌赛马 策略,先将能力值排序,从小到大枚举每一个登山队员找到最靠右的合法匹配位置,这样构造下来字典序是较小的,并且匹配数是最多的。

然后考虑在保证匹配数最多的情况下移动。贪心地,按能力值从大到小枚举队员。如果该队员当前有匹配的位置,那么找到最左端的未匹配的位置来置换,这样的位置是确定下来的;如果没有匹配的位置,那就随便找到一个最靠左没有被确定的位置,如果这个位置被其他人匹配过了,那就强制把那个人拆下来,把现在这个人换上去。因为比他小的人都有匹配,那这个人一定也有匹配。由于从大到小确定位置构造,这样的字典序一定最大。

具体维护方式可以使用两颗线段树,一棵维护没有被匹配的位置的最小值,一棵维护没有被确定的位置的最小值。支持单点修改,查最靠左、右最小值,线段树上二分即可。复杂度 \(\mathcal{O}(n\log n)\)

#include<bits/stdc++.h>
using namespace std;
constexpr int N = 5e5 + 5, Inf = 1e9;
int n, a[N], b[N], mch[N], ans[N];
struct ST{
	#define ls (id << 1)
	#define rs (id << 1 | 1)
	#define pushup(id) t[id].mn = min(t[ls].mn, t[rs].mn)
	struct node{ int l, r, mn; }t[N<<2];
	inline void build(int id, int l, int r){
		t[id] = node{l, r, 0};
		if(l == r) return t[id].mn = a[l], void();
		int mid = (l + r) >> 1;
		build(ls, l, mid), build(rs, mid+1, r);
		pushup(id);
	}
	inline void modify(int id, int pos, int val){
		if(pos <= 0 || pos > n) return;
		if(t[id].l == t[id].r) return t[id].mn = val, void();
		int mid = (t[id].l + t[id].r) >> 1;
		if(pos <= mid) modify(ls, pos, val);
		else modify(rs, pos, val);
		pushup(id);
	}
	inline int query_l(int id, int val){
		if(t[id].mn >= val) return 0;
		if(t[id].l == t[id].r) return t[id].l;
		if(t[ls].mn < val) return query_l(ls, val);
		else return query_l(rs, val);
	}
	inline int query_r(int id, int val){
		if(t[id].mn >= val) return 0;
		if(t[id].l == t[id].r) return t[id].l;
		if(t[rs].mn < val) return query_r(rs, val);
		else return query_r(ls, val);
	}
} ST1, ST2;
int main(){
	freopen("uphill.in", "r", stdin); freopen("uphill.out", "w", stdout);
	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];
	sort(b+1, b+1+n); ST1.build(1, 1, n); ST2.build(1, 1, n);
	for(int i=1, pos; i<=n; ++i){
		pos = ST1.query_r(1, b[i]);
		ans[mch[i] = pos] = i;
		ST1.modify(1, pos, Inf);
	} 
	for(int i=n, pos; i>=1; --i){
		if(mch[i]){
			ST1.modify(1, mch[i], a[mch[i]]);
			pos = ST1.query_l(1, b[i]);
			ans[mch[i]] = 0; ans[pos] = i;
		} else {
			pos = ST2.query_l(1, Inf);
			if(ans[pos]) mch[ans[pos]] = 0;
			ans[pos] = i;
		}
		ST1.modify(1, pos, Inf), ST2.modify(1, pos, Inf);
	}
	for(int i=1; i<=n; ++i) cout<<b[ans[i]]<<' ';
	return 0;
}
posted @ 2024-11-22 19:24  XiaoLe_MC  阅读(40)  评论(1)    收藏  举报