编程语言
首页 > 编程语言> > 2022“杭电杯”中国大学生算法设计超级联赛(2) 题解

2022“杭电杯”中国大学生算法设计超级联赛(2) 题解

作者:互联网

A. Static Query on Tree

将集合 \(|A|,|B|,|C|\) 内取出的点记为 \(a,\ b,\ c\),我们可以从题目条件中提取三个信息

① 满足要求的点一定在 a到c 的这条链上

② 满足要求的点一定在 b到c 的这条链上

③ 满足要求的点一定在 c 的子树内

利用树链剖分+线段树,我们可以在树上维护 \(a,\ b,\ c\) 三个标记,表示是否分别满足这三个条件,最后求出同时满足这三个条件的点的数量。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = (int)2e5 + 5;

struct Segment_Tree {
	struct Node {
	    int maxx, sum[4], tag[2];
	}tree[MAXN << 2];
	
	void Init(int l, int r, int p) {
		tree[p].sum[0] = r - l + 1;
		for(int i = 1; i < 4; i++) tree[p].sum[i] = 0;
		tree[p].tag[1] = 1, tree[p].tag[0] = 0;
	}
	
	void Calc(int l, int r, int p, int k) {
		for(int i = 3; i >= 0; i--) {
			if( (i | k) == i ) continue;
			tree[p].sum[i | k] += tree[p].sum[i];
			tree[p].sum[i] = 0;
		}
		tree[p].tag[0] |= k;
	}
	
	void PushUp(int l, int r, int p) {
		for(int i = 0; i < 4; i++) tree[p].sum[i] = tree[p << 1].sum[i] + tree[p << 1 | 1].sum[i];
	}
	
	void PushDown(int l, int r, int p) {
		int mid = l + r >> 1;
		if(tree[p].tag[1]) {
			Init(l, mid, p << 1);
			Init(mid + 1, r, p << 1 | 1);
			tree[p].tag[1] = 0;
		}
		if(tree[p].tag[0]) {
			Calc(l, mid, p << 1, tree[p].tag[0]);
			Calc(mid + 1, r, p << 1 | 1, tree[p].tag[0]);
			tree[p].tag[0] = 0;
		}	
	}
	
	void Build(int l, int r, int p) {
		Init(l, r, p);
		if(l == r) return ;
	    int mid = l + r >> 1;
	    Build(l, mid, p << 1);
	    Build(mid + 1, r, p << 1 | 1);
	    PushUp(l, r, p);
	}
	
	void Modify(int nl, int nr, int l, int r, int p, int k) {
	    if(nl <= l && nr >= r) return void( Calc(l, r, p, k) );
	    PushDown(l, r, p);
	    int mid = l + r >> 1;
	    if(nl <= mid) Modify(nl, nr, l, mid, p << 1, k);
	    if(nr > mid) Modify(nl, nr, mid + 1, r, p << 1 | 1, k);
	    PushUp(l, r, p);
	}
	
	int Query(int nl, int nr, int l, int r, int p) {
		int mid = l + r >> 1, res = 0;
		if(nl <= l && nr >= r) {
			res = tree[p].sum[3];
			Init(l, r, p);
			return res;
		}
		PushDown(l, r, p);
		if(nl <= mid) res += Query(nl, nr, l, mid, p << 1);
		if(nr > mid) res += Query(nl, nr, mid + 1, r, p << 1 | 1);
		PushUp(l, r, p);
		return res;
	}
}Seg;

int fa[MAXN], sze[MAXN], son[MAXN], dep[MAXN];
int id[MAXN], val[MAXN], top[MAXN], cnt;
vector<int> G[MAXN];
int n, q, a[MAXN], b[MAXN], c[MAXN];

void DFS1(int u, int f) {
    fa[u] = f, sze[u] = 1, son[u] = 0, dep[u] = dep[f] + 1;
    int maxsize = -1;
    for(auto v : G[u]) {
        DFS1(v, u);
        if(sze[v] > maxsize) maxsize = sze[v], son[u] = v;
        sze[u] += sze[v];
    }
}

void DFS2(int u, int topu) {
    id[u] = ++cnt, val[cnt] = u, top[u] = topu;
    if(son[u] == 0) return ;
    DFS2(son[u], topu);
    for(auto v : G[u]) if(v != son[u] && v != fa[u]) DFS2(v, v);
}

void Modify(int u, int k) {
    int v = 1;
    while(top[u] != top[v]) {
        if(dep[top[u]] < dep[top[v]]) swap(u, v);
        Seg.Modify(id[top[u]], id[u], 1, n, 1, k);
        u = fa[top[u]];
    }
    if(id[u] > id[v]) swap(u, v);
    Seg.Modify(id[u], id[v], 1, n, 1, k);
}

void Solve() {
    cin >> n >> q; cnt = 0;
    for(int i = 1; i <= n; i++) G[i].clear();
    for(int i = 2; i <= n; i++) { int u; cin >> u; G[u].push_back(i); }
    DFS1(1, 0), DFS2(1, 1), Seg.Build(1, n, 1);
    while(q--) {
        int A, B, C; cin >> A >> B >> C;
    	Seg.Init(1, 1, n);
        for(int i = 1; i <= A; i++) cin >> a[i], Modify(a[i], 1);
        for(int i = 1; i <= B; i++) cin >> b[i], Modify(b[i], 2);
        
		int ans = 0;
        for(int i = 1; i <= C; i++) {
        	cin >> c[i];
        	ans += Seg.Query(id[ c[i] ], id[ c[i] ] + sze[ c[i] ] - 1, 1, n, 1);
        }
        cout << ans << "\n";
    }
}

signed main()
{
    ios::sync_with_stdio(false); cin.tie(0);
    int T; cin >> T;
    while(T--) Solve();
    return 0;
}

B. C++ to Python

签到题,模拟即可

#include<bits/stdc++.h>
using namespace std;

string S;

void Solve() {
	cin >> S;
	for(int i = 0; i < S.length(); i++) {
		bool flag = 0;
		if(S[i] == '(') flag = 1;
		else if(S[i] == ')') flag = 1;
		else if(S[i] == ',') flag = 1;
		else if(S[i] == '-') flag = 1;
		else if(S[i] >= '0' && S[i] <= '9') flag = 1;
		if(flag) cout << (char)S[i];
	}
	cout << "\n";
}

signed main()
{
	int T; cin >> T;
	while(T--) Solve();
	return 0;
} 

C. Copy

考虑修改操作对后续的查询操作的影响:如果 \(x \leq r\) 就没影响,如果 \(x>r\) ,则相当于查询 \(x - (r - l + 1)\)。

正着考虑所有修改操作,发现从分裂区间的角度不好处理。利用正难则反的原则,我们倒着考虑所有修改操作,此时从合并区间的角度处理操作。

又因为输出所有答案的异或值,我们发现相同结果的两个查询可以抵消,一个结果可被利用0或1次,

设 \(dp[i]\) 为 \(a[i]\) 被利用几次,则dp值可以用bitset维护,有:

① 对于查询操作,\(dp[i] = dp[i] \oplus 1\),其中\(\oplus\)表示异或符号;

② 对于修改操作,我们令 \(i>r\) 的所有dp值往左移 \(r-l+1\) 位,并与 \(i \leq r\) 的所有dp值进行异或操作。

#include<bits/stdc++.h>
#define int long long
#define pir make_pair
#define pii pair<int, int>
#define fi first
#define se second
using namespace std;

const int MAXN = 1e5 + 5;

int n, q, a[MAXN], l[MAXN], r[MAXN], op[MAXN];
bitset<MAXN> vis; 

void Solve() {
	scanf("%lld%lld", &n, &q);
	for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
	for(int i = 1; i <= q; i++) {
		scanf("%lld", &op[i]);
		if(op[i] == 1) scanf("%lld%lld", &l[i], &r[i]);
		else scanf("%lld", &l[i]);
	}
	vis = 0;
	for(int i = q; i >= 1; i--) {
		if(op[i] == 1) {
			bitset<MAXN> cur, res1, res2;
			cur = 0, cur.flip(), cur <<= (r[i] + 1);
			res1 = (vis & cur) >> (r[i] - l[i] + 1);
			cur = 0, cur.flip(), cur >>= (MAXN - 1 - r[i]);
			res2 = (vis & cur);
			vis = res1 ^ res2;
		} else vis[ l[i] ].flip();
	}
	int ans = 0;
	for(int i = 1; i <= n; i++) if(vis[i]) ans ^= a[i];
	cout << ans << "\n";
}

signed main()
{
	int TT; scanf("%lld", &TT);
	while(TT--) Solve();
	return 0;
}  

E. Slayers Come

我们将解题过程分为两个步骤:

① 求出每个技能能杀死怪物的区间

② 对于①处理出来的 \(m\) 个区间,我们求出有多少种选择区间方案,满足选出来的区间能覆盖这n个点

用两个线段树处理这两个过程。

对于①,我们先考虑技能往左的情况,将不等式化为 \(a_j - b_{j-1} \geq L_i\) ,此时我们需要找到满足 \(a_j - b_{j-1} < L_i\) 的最大位置,用线段树二分即可解决。对于技能往右的情况同理。

对于②,我们先对所有区间按右端点升序排序,并设 \(dp[i]\) 为覆盖 \([1, i]\) 的方案数,则对于一个新加入的区间,有:

\[dp[r] = \sum_{i=l-1}^{r} dp[i] \\ dp[i] *= 2, \ i \in [1, l-2] \]

发现需要支持区间修改区间查询,线段树维护即可

#include<bits/stdc++.h>
#define int long long
#define pir make_pair
#define pii pair<int, int>
#define fi first
#define se second
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e5 + 5;
const int MOD = 998244353;

int n, m, a[MAXN], b[MAXN], f[MAXN];
pii s[MAXN];
vector<int> vec[MAXN];

struct Seg {
	int sum[MAXN << 2], minl[MAXN << 2], minr[MAXN << 2], add[MAXN << 2], mul[MAXN << 2], n;
	
	void PushUp(int p) {
		sum[p] = (sum[p << 1] + sum[p << 1 | 1]) % MOD;
		minl[p] = min(minl[p << 1], minl[p << 1 | 1]);
		minr[p] = min(minr[p << 1], minr[p << 1 | 1]);
	}
	
	void PushDown(int p, int l, int r) {
		int mid = l + r >> 1;
		mul[p << 1] = mul[p << 1] * mul[p] % MOD;
		mul[p << 1 | 1] = mul[p << 1 | 1] * mul[p] % MOD;
		add[p << 1] = (add[p << 1] * mul[p] % MOD + add[p]) % MOD;
		add[p << 1 | 1] = (add[p << 1 | 1] * mul[p] % MOD + add[p]) % MOD;
		sum[p << 1] = (sum[p << 1] * mul[p] % MOD + add[p] * (mid - l + 1) % MOD) % MOD;
		sum[p << 1 | 1] = (sum[p << 1 | 1] * mul[p] % MOD + add[p] * (r - mid) % MOD) % MOD;
		add[p] = 0, mul[p] = 1;
	}
	
	void Build(int l, int r, int p) {
		mul[p] = 1, add[p] = 0;
		if(l == r) {
			sum[p] = 0, minl[p] = a[l] - b[l - 1], minr[p] = a[l] - b[l + 1];
			return ;
		}
		int mid = l + r >> 1;
		Build(l, mid, p << 1);
		Build(mid + 1, r, p << 1 | 1);
		PushUp(p);
	}
	
	int QueryLeftPos(int nl, int nr, int l, int r, int p, int val) {
		int mid = l + r >> 1, res = -1;
		if(l == r) return minl[p] >= val ? -1 : l;
		if(nl <= l && nr >= r) {
			if(minl[p] >= val) return -1;
			if(minl[p << 1 | 1] < val) return QueryLeftPos(nl, nr, mid + 1, r, p << 1 | 1, val);
			else return QueryLeftPos(nl, nr, l, mid, p << 1, val);
		}
		
		if(nr > mid) res = max(res, QueryLeftPos(nl, nr, mid + 1, r, p << 1 | 1, val) );
		if(res > -1) return res;
		if(nl <= mid) res = max(res, QueryLeftPos(nl, nr, l, mid, p << 1, val) );
		return res;
	}
	
	int QueryRightPos(int nl, int nr, int l, int r, int p, int val) {
		int mid = l + r >> 1, res = INF;
		if(l == r) return minr[p] >= val ? INF : l;
		if(nl <= l && nr >= r) {
			if(minr[p] >= val) return INF;
			if(minr[p << 1] < val) return QueryRightPos(nl, nr, l, mid, p << 1, val);
			else if(minr[p << 1 | 1] < val) return QueryRightPos(nl, nr, mid + 1, r, p << 1 | 1, val);
		}
		
		if(nl <= mid) res = min(res, QueryRightPos(nl, nr, l, mid, p << 1, val) );
		if(res < INF) return res;
		if(nr > mid) res = min(res, QueryRightPos(nl, nr, mid + 1, r, p << 1 | 1, val) );
		return res;
	}
	
	int QuerySum(int nl, int nr, int l, int r, int p) {
		if(nl <= l && nr >= r) return sum[p];
		PushDown(p, l, r);
		int res = 0, mid = l + r >> 1;
		if(nl <= mid) res += QuerySum(nl, nr, l, mid, p << 1);
		if(nr > mid) res += QuerySum(nl, nr, mid + 1, r, p << 1 | 1);
		res %= MOD;
		return res;
	}
	
	void ModifyAdd(int nl, int nr, int l, int r, int p, int val) {
		if(l == r) {
			add[p] = (add[p] + val) % MOD;
			sum[p] = (sum[p] + val * (r - l + 1) % MOD) % MOD;
			return ;
		}
		int mid = l + r >> 1;
		if(nl <= mid) ModifyAdd(nl, nr, l, mid, p << 1, val);
		if(nr > mid) ModifyAdd(nl, nr, mid + 1, r, p << 1 | 1, val);
		PushUp(p);
	}

	void ModifyMul(int nl, int nr, int l, int r, int p, int val) {
		if(nl <= l && nr >= r) {
			mul[p] = mul[p] * val % MOD;
			add[p] = add[p] * val % MOD;
			sum[p] = sum[p] * val % MOD;
			return ;
		}
		int mid = l + r >> 1;
		if(nl <= mid) ModifyMul(nl, nr, l, mid, p << 1, val);
		if(nr > mid) ModifyMul(nl, nr, mid + 1, r, p << 1 | 1, val);
		PushUp(p);
	}
	
	void Init(int x) {
		n = x;
		Build(1, n, 1);
	}
}Left, Right, Sum;

void Solve() {
	scanf("%lld%lld", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%lld%lld", &a[i], &b[i]), f[i] = 0;
	
	b[0] = b[n + 1] = INF;
	Left.Init(n); Right.Init(n); Sum.Init(n + 1);
	for(int i = 1; i <= m; i++) {
		int m, L, R; scanf("%lld%lld%lld", &m, &L, &R);
		
		s[i] = pir(
			Left.QueryLeftPos(1, m, 1, n, 1, L),
			Right.QueryRightPos(m, n, 1, n, 1, R)
		);
		if(s[i].fi <= -1) s[i].fi = m;
		if(s[i].se >= INF) s[i].se = m;
	}
	
	for(int i = 1; i <= m; i++) swap(s[i].fi, s[i].se);
	sort(s + 1, s + 1 + m);
	for(int i = 1; i <= m; i++) swap(s[i].fi, s[i].se);
	
	f[0] = 1;
	Sum.ModifyAdd(1, 1, 1, n + 1, 1, 1);
	for(int i = 1; i <= m; i++) {
		int l = s[i].fi, r = s[i].se;
		f[r] = Sum.QuerySum(l, r + 1, 1, n + 1, 1);
		Sum.ModifyAdd(r + 1, r + 1, 1, n + 1, 1, f[r]);
		if(l - 1 >= 1) Sum.ModifyMul(1, l - 1, 1, n + 1, 1, 2);
	}
	cout << Sum.QuerySum(n + 1, n + 1, 1, n + 1, 1) << "\n";
}

signed main()
{
	int TT; scanf("%lld", &TT);
	while(TT--) Solve();
	return 0;
} 

F. Bowcraft

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
#define pir make_pair
#define pii pair<int, int>
#define fi first
#define se second
using namespace std;
const int MAXN = 1000 + 5;
const int MOD = 1e9 + 7;
const int INF = 1e18;

struct Node {
	int a, b;
	double w;
};

int K, A, B;
double f[MAXN];
vector<Node> vec;

bool cmp(const Node& a, const Node& b) {
	return a.w < b.w;
}

double min(double a, double b) {
	return a > b ? b : a;
}

void Solve() {
	cin >> K >> A >> B;
	vec.clear();
	for(int a = 1; a < A; a++) {
		for(int b = 0; b < B; b++) {
			double w = 1.0 * b * A / (B * a) - 1.0 * b / B;
			vec.push_back({a, b, w});
		}
	}
	sort(vec.begin(), vec.end(), cmp);
	f[0] = 0;
	for(int i = 1; i <= K; i++) {
		double sum1 = 0, sum2 = 0;
		int cnt = 0;
		f[i] = INF;
		for(auto k : vec) {
			int a = k.a, b = k.b, w = k.w;
			sum1 += 1.0 * a / A + 1.0 * b / B - 1.0 * a * b / (A * B);
			sum2 += (1.0 * (A - a) / A);
			cnt++;
			double cur = A * B + sum1 * f[i - 1];
			cur /= (1.0 * cnt - sum2);
			f[i] = min(f[i], cur);
		}
	}
	printf("%.3lf\n", f[K]);
}

signed main()
{
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin >> T;
	while(T--) Solve();
	return 0;
}

G. Snatch Groceries

根据贪心思想,首先按 \(earliest\) 为第一关键字,\(latest\) 为第二关键字升序排序,

枚举下一个区间,判断当前区间是否与上一个区间相交即可。

#include<bits/stdc++.h>
#define int long long
#define pir make_pair
#define pii pair<int, int>
#define fi first
#define se second
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e5 + 5;

int n;
pii a[MAXN];

void Solve() {
	scanf("%lld", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%lld%lld", &a[i].fi, &a[i].se);
	}
	sort(a + 1, a + 1 + n);
	int ans = 0, flag = 1;
	for(int i = 1; i < n; i++) {
		if(a[i].se < a[i + 1].fi) ans++;
		else { flag = 0; break; }
	}
	if(flag) ans++;
	cout << ans << "\n";
}

signed main()
{
	int TT; scanf("%lld", &TT);
	while(TT--) Solve();
	return 0;
} 

H. Keyboard Warrior

K. DOS Card

设 \(i,\ j,\ k,\ l\) 为区间内选出来的四个数的下标,令其组成两对,有两种情况:

① \(a_i^2+a_j^2-a_k^2-a_l^2\) ② \(a_i^2-a_j^2+a_k^2-a_l^2\)

为了简化后续操作,我们将其称为 ①\(++--\) ②\(+-+-\) (+-分别代表这四个数对答案贡献的正负)

逐步拆解成两个部分,有

\[\left\{ \begin{array}{**lr**} ++-- \left\{ \begin{array}{**lr**} +,+-- \\ ++,-- \\ ++-,- \\ \end{array} \right. \\ +-+- \left\{ \begin{array}{**lr**} +,-+- \\ +-,+- \\ +-+,- \\ \end{array} \right. \end{array} \right. \]

发现对于\(-,+,--,++\)的情况,我们用\(Max1, Max2,Min1, Min2\)维护

对于\(+-\)的情况,我们用\(aPairMax\)维护

对于\(++-,+-+\)的情况,我们用\(ValAddMax\)维护,因为这两种情况下,剩下的\(-\)只能放置于一端,所以只需要用一个变量维护

对于\(+--,-+-\)的情况,我们用\(ValMinusMax\)维护,因为这两种情况下,剩下的\(+\)只能放置于一端,所以只需要用一个变量维护

对于这\(ValAddMax,\ ValMinusMax\)的维护,我们将上述四种情况继续拆解即可

最后再用\(twoPairMax\)维护\(++--,+-+-\)的最大值

线段树的\(PushUp\)操作即是维护上述操作的过程

#include<bits/stdc++.h>
#define int long long
#define pir make_pair
#define pii pair<int, int>
#define fi first
#define se second
using namespace std;

const int MAXN = 4e5 + 5;
const int INF = 1e18;

struct Node {
	int Max1, Max2;
	int Min1, Min2;
	int aPairMax;
	int twoPairMax;
	int ValAddMax;
	int ValMinusMax;
	int len;
	
	void Init() {
		Max1 = Max2 = -INF;
		Min1 = Min2 = INF;
		aPairMax = -INF;
		twoPairMax = -INF;
		ValAddMax = -INF;
		ValMinusMax = -INF;	
	}
}tree[MAXN << 2];

int n, m, a[MAXN];

Node PushUp(Node ls, Node rs) {
	Node res;
	res.len = ls.len + rs.len;
	
	res.Max1 = max(ls.Max1, rs.Max1);
	
	res.Max2 = max( min(ls.Max1, rs.Max1), max(ls.Max2, rs.Max2) );
	
	res.Min1 = min(ls.Min1, rs.Min1);
	
	res.Min2 = min( max(ls.Min1, rs.Min1), min(ls.Min2, rs.Min2) );
	
	res.aPairMax = max({
		ls.aPairMax, 
		rs.aPairMax, 
		ls.Max1 - rs.Min1
	});
	
	res.twoPairMax = max({
		ls.twoPairMax, 
		rs.twoPairMax,
		ls.aPairMax + rs.aPairMax,
		ls.Max1 + ls.Max2 - rs.Min1 - rs.Min2,
		ls.ValAddMax - rs.Min1,
		ls.Max1 + rs.ValMinusMax
	});
	
	res.ValAddMax = max({
		ls.ValAddMax,
		rs.ValAddMax,
		ls.aPairMax + rs.Max1,
		rs.aPairMax + ls.Max1
	});
	if(ls.len >= 2) res.ValAddMax = max(res.ValAddMax, ls.Max1 + ls.Max2 - rs.Min1);
	if(rs.len >= 2) res.ValAddMax = max(res.ValAddMax, ls.Max1 + rs.Max1 - rs.Min1);
	
	res.ValMinusMax = max({
		ls.ValMinusMax,
		rs.ValMinusMax,
		ls.aPairMax - rs.Min1,
		rs.aPairMax - ls.Min1
	});
	if(ls.len >= 2) res.ValMinusMax = max(res.ValMinusMax, ls.Max1 - ls.Min1 - rs.Min1);
	if(rs.len >= 2) res.ValMinusMax = max(res.ValMinusMax, ls.Max1 - rs.Min1 - rs.Min2);
	return res;
}

void Build(int l, int r, int p) {
	tree[p].Init();
	if(l == r) {
		tree[p].Max1 = a[l] * a[l];
		tree[p].Min1 = a[l] * a[l];
		tree[p].len = 1;
		return ;
	}
	int mid = l + r >> 1;
	Build(l, mid, p << 1);
	Build(mid + 1, r, p << 1 | 1);
	tree[p] = PushUp(tree[p << 1], tree[p << 1 | 1]);
}

Node Query(int nl, int nr, int l, int r, int p) {
	if(nl <= l && nr >= r) return tree[p];
	int mid = l + r >> 1;
	if(nr <= mid) return Query(nl, nr, l, mid, p << 1);
	else if(nl > mid) return Query(nl, nr, mid + 1, r, p << 1 | 1);
	else return PushUp( Query(nl, nr, l, mid, p << 1), Query(nl, nr, mid + 1, r, p << 1 | 1) );
}

void Solve() {
	scanf("%lld%lld", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
	Build(1, n, 1);
	
	while(0) {
		int l, r; cin >> l >> r;
		Node cur = Query(l, r, 1, n, 1);
		cout << cur.Max1 << " Max1\n";
		cout << cur.Max2 << " Max2\n";
		cout << cur.Min1 << " Min1\n";
		cout << cur.Min2 << " Min2\n";
		cout << cur.aPairMax << " aPairMax\n";
		cout << cur.twoPairMax << " twoPairMax\n";
		cout << cur.ValAddMax << " ValAddMax\n";
		cout << cur.ValMinusMax << " ValMinusMax\n";
	}
	
	while(m--) {
		int l, r; scanf("%lld%lld", &l, &r);
		printf("%lld\n", Query(l, r, 1, n, 1).twoPairMax );
	}
}

signed main()
{
	int TT; scanf("%lld", &TT);
	while(TT--) Solve();
	return 0;
}  

L. Luxury cruise ship

发现7,31,365三个数互质,可以先预处理出7 * 31 * 365的背包,大于7 * 31 * 365的部分直接用365填充即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int INF = 0x3f3f3f3f;

int f[90005];

signed main()
{
	int n = 80000, lcm = 79205;
	memset(f, 0x3f, sizeof f);
	f[0] = 0;
	for(int i = 1; i <= n; i++) {
		if(i >= 7) f[i] = min(f[i], f[i - 7] + 1);
		if(i >= 31) f[i] = min(f[i], f[i - 31] + 1);
		if(i >= 365) f[i] = min(f[i], f[i - 365] + 1);
	}
	
	int T; cin >> T;
	while(T--) {
		cin >> n;
		int ans = 0;
		ans += (n / lcm) * (lcm / 365);
		n %= lcm;
		ans += f[n];
		if(f[n] >= INF) ans = -1;
		cout << ans << "\n";
	}
	return 0;
} 

标签:return,int,题解,mid,MAXN,2022,res,杭电杯,define
来源: https://www.cnblogs.com/Orzjh/p/16519775.html