首页 > 其他分享 >AtCoder Regular Contest 150 F Constant Sum Subsequence

AtCoder Regular Contest 150 F Constant Sum Subsequence

时间:2022-12-14 18:56:03浏览次数:85  
标签:150 typedef Constant nxt mid long AtCoder define mathrm

AtCoder 传送门

洛谷传送门

定义 \(\mathrm{nxt}(i,x)\) 为最小的 \(j\) 满足 \(a_j = x\) 且 \(j > i\),\(\mathrm{pre}(i,x)\) 为最大的 \(j\) 满足 \(a_j = x\) 且 \(j < i\)。

有了上面的定义后,考虑 dp。设 \(f_s\) 表示最小的 \(i\),满足所有和为 \(s\) 的正整数序列都是 \(a_1,a_2,...,a_i\) 的子序列。则答案为 \(f_S\)(此处的 \(S\) 为原题面中的 \(S\)),初值 \(f_0 = 0\)。

考虑如何转移。枚举一个数 \(x\),那么所有和为 \(s-x\) 的序列都可以在末尾接上一个 \(x\) 得到,所以 \(f_s \ge \mathrm{nxt}(f_{s-x},x)\)。可得 \(f_s = \max\limits_{x=1}^s \mathrm{nxt}(f_{s-x},x)\)。如果使用刷表法,则 \(f_s\) 已知,\(f_{s+x} \gets \max(f_{s+x},\mathrm{nxt}(f_s,x))\)。这样朴素转移是 \(O(S^2 \log n + n)\) 的。

考虑分治优化。设当前区间为 \([l,r]\),令 \(mid = \left\lfloor\frac{l+r}{2}\right\rfloor\)。先计算 \([l,mid]\),再考虑 \([l,mid]\) 对 \([mid+1,r]\) 的贡献。还是先枚举一个 \(x\),由 \(f\) 的转移式可得 \(f\) 有单调性,则 \(\forall i \in [mid+1,r],f_i > f_{mid}\)。则我们只需要考虑可能对右区间有贡献的 \(s\),即 \(s\) 满足 \(\mathrm{nxt}(f_s,x) = \mathrm{nxt}(f_{mid},x)\)。这些 \(s\) 形成了一段区间,而这个区间的左端点就是最小的 \(i\) 满足 \(f_i \ge \mathrm{pre}(f_{mid},x)\)。于是对这段区间内的 \(s\),令 \(f_{s+x} \gets \max(f_{s+x},\mathrm{nxt}(f_{mid},x))\)。则我们需要一个区间取 \(\max\),单点查询的数据结构。可以用标记永久化的线段树实现。

总时间复杂度 \(O(n + S \log S(\log S + \log n))\)。

code
/*

p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline ll read() {
    char c = getchar();
    ll x = 0;
    for (; !isdigit(c); c = getchar()) ;
    for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x;
}

const int maxn = 1500100;
const int maxm = 200100;

ll n, m, a[maxn], f[maxm];
vector<ll> app[maxm];

namespace SGT {
	ll tree[maxm << 2];
	
	void update(int rt, int l, int r, int ql, int qr, ll x) {
		if (ql <= l && r <= qr) {
			tree[rt] = max(tree[rt], x);
			return;
		}
		int mid = (l + r) >> 1;
		if (ql <= mid) {
			update(rt << 1, l, mid, ql, qr, x);
		}
		if (qr > mid) {
			update(rt << 1 | 1, mid + 1, r, ql, qr, x);
		}
	}
	
	ll query(int rt, int l, int r, int x) {
		if (l == r) {
			return tree[rt];
		}
		int mid = (l + r) >> 1;
		if (x <= mid) {
			return max(tree[rt], query(rt << 1, l, mid, x));
		} else {
			return max(tree[rt], query(rt << 1 | 1, mid + 1, r, x));
		}
	}
}

inline ll getnxt(ll x, ll y) {
	ll t = (x - 1) % n + 1, k = x - t;
	auto it = upper_bound(app[y].begin(), app[y].end(), t);
	if (it == app[y].end()) {
		return app[y].front() + k + n;
	} else {
		return *it + k;
	}
}

inline ll getpre(ll x, ll y) {
	ll t = (x - 1) % n + 1, k = x - t;
	auto it = upper_bound(app[y].begin(), app[y].end(), t);
	if (it == app[y].begin()) {
		return app[y].back() + k - n;
	} else {
		return *(--it) + k;
	}
}

void solve(int l, int r) {
	if (l == r) {
		return;
	}
	int mid = (l + r) >> 1;
	solve(l, mid);
	for (int i = 1; i <= r - l; ++i) {
		int R = min(r - i, mid);
		int L = lower_bound(f + l, f + mid + 1, getpre(f[R], i)) - f;
		L = max(L, mid + 1 - i);
		SGT::update(1, 0, m, L + i, R + i, getnxt(f[R], i));
	}
	for (int i = mid + 1; i <= r; ++i) {
		f[i] = SGT::query(1, 0, m, i);
	}
	solve(mid + 1, r);
}

void solve() {
	n = read();
	m = read();
	for (int i = 1; i <= n; ++i) {
		a[i] = read();
		app[a[i]].pb(i);
	}
	solve(0, m);
	printf("%lld\n", f[m]);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:150,typedef,Constant,nxt,mid,long,AtCoder,define,mathrm
From: https://www.cnblogs.com/zltzlt-blog/p/16982956.html

相关文章

  • atcoder beginner 281 DEFG 题解
    比赛链接:https://atcoder.jp/contests/abc281题解:D\(dp[i][j][k]\)表示考虑到第i个数,集合加入了\(k\)个数,余数为\(j\)的答案转移即可//bySkyRainWind#inclu......
  • AtCoder Beginner Contest 281
    A-CountDown(abc281a)题目大意给定\(n\),输出\(n\)到\(1\)。解题思路直接输出即可。神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=l......
  • atcoder beginner contest 144 Gluttony(二分答案)
    题目大意:有an,bn,我们找到an和bn每个元素的一种一一对应关系。使得min(max(ai*bi))。已知我们可以进行操作让an中的任一个元素减少1。操作数最大为k,问我们怎么操作,可以min(......
  • atcoder ABC 281(A-C)
    A要求你从N开始,一直打印到0。NN-1......3210简单#include<iostream>usingnamespacestd;intn;intmain(){ cin>>n; for(inti=n;i>=0;i--)cout<<i<<en......
  • AtCoder 问题乱做集1
    AGC014D BlackandWhiteTree*2266题目大意:两个人在$n$个节点的树上交替染色,先手染白色,后手染黑色。若染完之后有白点不与黑点相邻则先手胜,反之后手胜。求这棵树......
  • AtCoder Beginner Contest 242 F Black and White Rooks
    洛谷传送门AtCoder传送门不错的组合计数题。因为黑车和白车不能在同一行或者同一列,所以可以考虑枚举黑车有\(i\)行\(k\)列的位置放,白车有\(j\)行\(l\)列的位置......
  • AtCoder Beginner Contest 281
    \(\mathtt{rank:1119th}\)\(\mathtt{problem}\)\(\mathtt{A}\)\(\mathtt{B}\)\(\mathtt{C}\)\(\mathtt{D}\)\(\mathtt{E}\)\(\mathtt{F}\)\(\mathtt{G}\)\(\ma......
  • AtCoder Beginner Contest 281
    https://atcoder.jp/contests/abc281A-CountDown原题链接题意给出一个数\(n\),按降序输出所有小于或等于\(n\)的非负整数。分析签到题,循环并输出从\(n\)到\(......
  • 【atcoder abc281_d】动态规划
    importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;/***@authorfishcanfly*/publicclassMain{/***......
  • AtCoder Beginner Contest 281
    比赛链接A-CountDownA题题面直接输出即可B-SandwichNumberB题题面这道题首先判断开头结尾是否为大写字母,然后判断总长度是否为8,然后对中间一段转数字即可。C......