省流:\(66 + 100 + 50\)。蓝紫黑。T1 6人过,T2 20人过,成分复杂。
T1
原题:P6571。
题解:感性理解题目中的性质,其中一个是答案 \(\leq k\),还有一个是我们一定可以找到一种给边定向的方案,使得每个点出度 \(\leq k\),构造方案具体可以每次找出度数最小的点,将与这个点相连且还没定向过的边都定为出边,并更新连向的点的度数。找到定向方案以后就可以枚举一个点,\(2^k\) 枚举最大团中的点,最后 \(\Theta(k)\) check 一下就行。时间复杂度 \(O(nk2^k)\)。
代码:
闲话:考场上不了解最大团的复杂度,直接写了个板子上去就跑路了,时间复杂度貌似是 \(\Theta(rand())\)。
T2
原题:P9991。
容易把题目转化为对于每一种颜色,把这个颜色去掉,求 \([l,r]\) 的最长连续段的最大值,把连续段分为三部分,第一部分为左端点到第一个这个颜色, 第二部分为右端点到最后一个这个颜色,第三部分为两个这个颜色中间的段。前两个部分可以用类似区间数颜色单 log 做法,只保留第一个/最后一个同种颜色的,容易用线段树二分做到单 log,第三部分依然考虑扫描线,右端点向右移动,设新增的颜色上一个位置为 \(lst\),那么对于左端点在 \([1,lst]\) 之间的询问,答案会与这个段长度取 max,于是只需要实现一个区间取 max,单点查询的数据结构即可,好像要写吉司机?发现是单点查询所以直接暴力下传 tag 或者标记永久化即可。
时间复杂度 \(O(n \log n)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace IO {
constexpr int S = (1 << 21);
int digital = 2;
bool is_round = 1;
char b[S], *m = b, *n = b, g[S], *p = g;
inline void f() { fwrite(g, 1, p - g, stdout), p = g; }
struct R {
inline bool w(char c) { return 47 < c && c < 58; }
inline bool y(char c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t'; }
inline char i() { if (m == n) n = (m = b) + fread(b, 1, S, stdin); return m == n ? ' ' : *m++; }
template <class T> inline R &operator>>(T &x) { char c = i(); T f = 1; for (x = 0; !w(c);) { if(c == '-') f = -1; c = i(); } while (w(c)) x *= 10, x += c ^ 48, c = i(); x *= f; return *this; }
inline R &operator>>(char *s) { int l = 0; char c; operator>>(c); for (; !y(c); s[l++] = c, c = i()) ; s[l] = '\0'; return *this; }
inline R &operator>>(string &s) { s = ""; char c = i(); while(y(c)) c = i(); while(!y(c)) s += c, c = i(); return *this; }
inline R &operator>>(double &x) { double t = 1, s = 0; char c = i(); for (x = 0; !w(c); c = i()) s = (c == '-'); for (; w(c); c = i()) x = x * 10 + c - 48; if (c == '.') for (c = i(); w(c); c = i()) x += (t /= 10.0) * (c - 48), s && (x = -x); return *this; }
inline R &operator>>(char &c) { do c = i(); while (y(c)); return *this; }
template<class T> void tie(T x) {}
} cin;
#define endl '\n'
struct W {
inline void o(char c) { *p++ = c; if (p - g == S) f(); }
template <class T> inline W &operator<<(T x) { if (!x) return o(48), *this; if(x < 0) o('-'), x = -x; static int s[64], t = 0; while (x) s[++t] = x % 10, x /= 10; while (t) o(s[t--] + 48); return *this; }
inline W &operator<<(char c) { o(c); return *this; }
template <class T> inline W &operator<<(T *s) { int c = 0; while (s[c]) o(s[c++]); return *this; }
inline W &operator<<(double x) { int k = 0; if(x < 0) o('-'), x = -x; if(is_round) x += 5 * pow(10, -digital - 1); operator<<((int)x), o('.'), x -= (int)x; while (k++ < digital) o((int)(x *= 10) + 48), x -= (int)x; return *this; }
inline W &operator<<(string s) { for(int i = 0; s[i] ^ '\0'; ++i) o(s[i]); return *this; }
template<class T> void tie(T x) {}
~W() { f(); }
} cout;
struct E { template <class T> E &operator<<(T x) { return *this; } } cerr;
} ;
#define cin IO::cin
#define cout IO::cout
const int N=2e6+5;
vector<int> ve[N];
int n,m,a[N],lst[N],ans[N];
struct node {int l,r,id;}q[N];
struct segtree {
int L[N<<2],R[N<<2],val[N<<2];
void build_tree(int l,int r,int id=1) {
L[id]=l,R[id]=r,val[id]=0;
if(l==r) return;
int mid=l+r>>1;
build_tree(l,mid,id<<1),build_tree(mid+1,r,id<<1|1);
}
void add(int x,int y,int id=1) {
if(L[id]==x&&R[id]==x) {
val[id]+=y;
return;
}
int mid=L[id]+R[id]>>1;
if(x<=mid) add(x,y,id<<1);
else add(x,y,id<<1|1);
val[id]=val[id<<1]+val[id<<1|1];
}
int mn(int id) {
if(!val[id]) return 0;
if(L[id]==R[id]) return L[id];
if(val[id<<1]) return mn(id<<1);
else return mn(id<<1|1);
}
int mx(int id) {
if(!val[id]) return 0;
if(L[id]==R[id]) return L[id];
if(val[id<<1|1]) return mx(id<<1|1);
else return mx(id<<1);
}
int querymn(int l,int r,int id=1) {
if(L[id]>=l&&R[id]<=r) return mn(id);
int mid=L[id]+R[id]>>1,ans=0;
if(l<=mid) ans=querymn(l,r,id<<1);
if(r>mid&&!ans) ans=querymn(l,r,id<<1|1);
return ans;
}
int querymx(int l,int r,int id=1) {
if(L[id]>=l&&R[id]<=r) return mx(id);
int mid=L[id]+R[id]>>1,ans=0;
if(r>mid) ans=querymx(l,r,id<<1|1);
if(l<=mid&&!ans) ans=querymx(l,r,id<<1);
return ans;
}
}t1,t2;
struct ibengbuzhu {
int L[N<<2],R[N<<2],tag[N<<2];
void build_tree(int l,int r,int id=1) {
L[id]=l,R[id]=r,tag[id]=0;
if(l==r) return;
int mid=l+r>>1;
build_tree(l,mid,id<<1),build_tree(mid+1,r,id<<1|1);
}
void modify(int l,int r,int x,int id=1) {
if(L[id]>=l&&R[id]<=r) {
tag[id]=max(tag[id],x);
return;
}
int mid=L[id]+R[id]>>1;
if(l<=mid) modify(l,r,x,id<<1);
if(r>mid) modify(l,r,x,id<<1|1);
}
int query(int x,int id=1) {
if(L[id]==R[id]) return tag[id];
int mid=L[id]+R[id]>>1;
if(x<=mid) return max(tag[id],query(x,id<<1));
else return max(tag[id],query(x,id<<1|1));
}
}t3;
int main() {
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=m; i++) cin>>q[i].l>>q[i].r,q[i].id=i;
t1.build_tree(1,n),t2.build_tree(1,n),t3.build_tree(1,n);
for(int i=1; i<=m; i++) ve[q[i].r].push_back(i);
for(int i=1; i<=n; i++) {
if(lst[a[i]]) t1.add(lst[a[i]],-1),t3.modify(1,lst[a[i]],i-lst[a[i]]-1);
t1.add(i,1),lst[a[i]]=i;
for(int j=0; j<ve[i].size(); j++) ans[q[ve[i][j]].id]=max(ans[q[ve[i][j]].id],max(q[ve[i][j]].r-t1.querymn(q[ve[i][j]].l,q[ve[i][j]].r),t3.query(q[ve[i][j]].l)));
}
for(int i=1; i<=m; i++) ve[q[i].r].clear();
for(int i=1; i<=n; i++) lst[a[i]]=0;
for(int i=1; i<=m; i++) ve[q[i].l].push_back(i);
for(int i=n; i>=1; i--) {
if(lst[a[i]]) t2.add(lst[a[i]],-1);
t2.add(i,1),lst[a[i]]=i;
for(int j=0; j<ve[i].size(); j++) ans[q[ve[i][j]].id]=max(ans[q[ve[i][j]].id],t2.querymx(q[ve[i][j]].l,q[ve[i][j]].r)-q[ve[i][j]].l);
}
for(int i=1; i<=m; i++) cout<<ans[i]<<"\n";
return 0;
}
闲话:原题极其卡常,模拟赛能过完全是因为时限多开了 2s/kx。
T3
原题:P9996。
还不会。
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库