其他分享
首页 > 其他分享> > [Contest on 2022.4.12] 我又来水博客了

[Contest on 2022.4.12] 我又来水博客了

作者:互联网

这场比赛的题目名真的太不走心了

\(\cal T_1\) 史莱姆 \(\rm A\)

\(\mathbb{Description}\)

史莱姆有一串长度为 \(n\) 的彩灯,其中第 \(i\) 盏彩灯的颜色为 \(a_i\).

史莱姆将这串彩灯剪成若干段并装饰在房间里,每一段彩灯的美丽度为这段彩灯的颜色形成的集合的 \(\rm mex\)。由于彩灯之间的奇特相互作用,整个房间的美丽度为每段彩灯的美丽度的积。史莱姆想知道所有剪彩灯的方案的美丽度之和是多少。答案对 \(998244353\) 取模。

\(n\le 10^6,0\le a_i\le n\).

\(\mathbb{Solution}\)

首先可以想到 \(dp_i=\sum dp_j\cdot \text{mex}(j+1,i)\),然后我就死了:先开始想 \(\rm mex\) 有易撤销的性质,所以考虑用贡献法,将 \(dp_j\) 乘上系数贡献到后面的 \(\mathtt{dp}\) 值,但问题是 \(\text{mex}(j+1,i)\) 显然在 \(j\) 增加的时候会改变,无法维护(虽说修改时是区间赋值,但事实上这个操作并没有区间乘/加好做)。

既然区间赋值不好做,我们能否考虑将 \(\rm mex\) 相同的 \(\mathtt{dp}\) 值分类处理呢?显然对于右端点固定的 \(\rm mex\) 值是单调不升的,每个 \(\rm mex\) 值就统治了一段区间 \([L_i,R_i]\). 假设加入 \(a_i\),我们找到 \(a_i\) 对应的区间 \([L,R]\),显然只有这一段区间的 \(\rm mex\) 值会受到影响:先找到 \([R,i]\) 的 \(\rm mex\),设其为 \(k\),我们找到 \(i\) 之前第一个值为 \(k\) 的位置 \(p\),那么 \([p+1,R]\) 的 \(\rm mex\) 就都更改为 \(k\),然后接着递归下去即可。

一个需要注意的点是 \(dp_j\) 和 \(\text{mex}(j+1,i)\) 的下标相差 \(1\),方便的方法是直接令 \(dp_1=1\),也就是将 \(\mathtt{dp}\) 值整体右移了一位。

时间复杂度?考虑每次至多删除一种 \(\rm mex\) 值,而总共有 \(n+1\) 种 \(\rm mex\) 值,所以是 \(\mathcal O(n\log n)\) 的。

\(\mathbb{Code}\)

#include <cstdio>
#define print(x,y) write(x),putchar(y)

template <class T>
inline T read(const T sample) {
	T x=0; char s; bool f=0;
	while((s=getchar())>'9' || s<'0')
		f |= (s=='-');
	while(s>='0' && s<='9')
		x = (x<<1)+(x<<3)+(s^48),
		s = getchar();
	return f?-x:x;
}

template <class T>
inline void write(T x) {
	static int writ[50],tp=0;
	if(x<0) putchar('-'),x=-x;
	do writ[++tp] = x-x/10*10, x/=10; while(x);
	while(tp) putchar(writ[tp--]^48);
}

# include <iostream>
using namespace std;

const int maxn = 1e6+5;
const int mod = 998244353;

inline int dec(int x,int y) { return x-y<0?x-y+mod:x-y; }
inline int inc(int x,int y) { return x+y>=mod?x+y-mod:x+y; }

int L[maxn],R[maxn],node[maxn],las[maxn];
int n,a[maxn],dp[maxn],ans,mn[maxn<<2];

void build(int o,int l,int r) {
    if(l==r) return node[l]=o, void();
    int mid = l+r>>1; 
    build(o<<1,l,mid); build(o<<1|1,mid+1,r);
}
void modify(int p,int k) {
    mn[p=node[p]] = k;
    while(p>>=1) mn[p] = min(mn[p<<1],mn[p<<1|1]);
}
int ask(int o,int l,int r,int p) {
    if(l==r) return r; int mid = l+r>>1;
    return mn[o<<1]<p? ask(o<<1,l,mid,p): ask(o<<1|1,mid+1,r,p);
}

int main() {
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
    n=read(9); dp[1]=L[0]=1, R[0]=n;
    for(int i=1;i<=n;++i) a[i]=read(9), L[i]=n+1;
    build(1,0,n);
    for(int i=1;i<=n;++i) { 
        modify(a[i],las[a[i]]=i);
        if(!R[a[i]]) { dp[i+1] = inc(dp[i],ans); continue; }
        int l=L[a[i]], r=R[a[i]]; L[a[i]]=n+1, R[a[i]]=0;
        ans = dec(ans,1ll*a[i]*dec(dp[r],dp[l-1])%mod);
        while(l<=r) { 
            int mex = ask(1,0,n,r), p = max(l-1,las[mex]);
            ans = inc(ans,1ll*mex*dec(dp[r],dp[p])%mod);
            L[mex] = min(L[mex],p+1), R[mex] = max(R[mex],r);
            r = p;
        } 
        dp[i+1] = inc(dp[i],ans);
    }
    print(ans,'\n');
    return 0;
}

\(\cal T_2\)

\(\mathbb{Description}\)

\(\mathbb{Solution}\)

\(\mathbb{Code}\)


\(\cal T_3\) 史莱姆 \(\rm C\)

\(\mathbb{Description}\)

史莱姆有一张无向图,最开始图仅有 \(0\) 号节点。现在有 \(n\) 次操作,每次操作为以下 \(5\) 种之一(不妨假设每次操作前这张图的节点编号区间为 \([l,r]\)):

  1. 删去 \(l\) 号节点,并删去 \(l\) 号节点连接的所有边;
  2. 删去 \(r\) 号节点,并删去 \(r\) 号节点连接的所有边;
  3. 增加 \(l-1\) 号节点,并连接 \(\min\{k-1,r-l+1\}\) 条边,第 \(i\) 条边连接 \(l-1,l-1+i\),边有边权;
  4. 增加 \(r+1\) 号节点,并连接 \(\min\{k-1,r-l+1\}\) 条边,第 \(i\) 条边连接 \(r+1,r+1-i\),边有边权。
  5. 对当前图询问最小生成树的边权和。

输入保证任意时刻 \(l\le r\).

\(2\le k\le 10, n\le 5\cdot 10^5\).

\(\mathbb{Solution}\)

不会正解,所以写了一发 \(\rm lct\),结果草过去了 /xk.

\(\mathbb{Code}\)

# include <cstdio>
# include <cctype>
# define print(x,y) write(x), putchar(y)

template <class T>
inline T read(const T sample) {
	T x=0; char s; bool f=0;
	while(!isdigit(s=getchar())) f|=(s=='-');
	for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
	return f? -x: x;
}
template <class T>
inline void write(T x) {
	static int writ[50], w_tp=0;
	if(x<0) putchar('-'), x=-x;
	do writ[++w_tp]=x-x/10*10, x/=10; while(x);
	while(putchar(writ[w_tp--]^48), w_tp);
}

# include <map>
# include <vector>
# include <random>
# include <cstring>
# include <iostream>
using namespace std;
typedef long long ll;
typedef pair <int,int> par;

const int maxn = 5e5+5;

bool vis[maxn*10];
ll cur,ans[maxn];
map <int,int> reID;
int SEED,k,n,cnt,L,R,idx,T,rec[maxn*10],now;
struct edge {
	int id,t;
	edge() {}
	edge(int ID,int ti):id(ID),t(ti) {}
};
struct Edge { int u,v,w; } E[maxn*10];
vector <edge> e[maxn];
vector <int> g[maxn<<2];

namespace random_Generator {
 	mt19937 engine;
	void initialize(int Seed) { engine.seed(Seed); }
	int getVal() { return uniform_int_distribution <int> (0,1e9)(engine); }
}

namespace lct {

struct node { bool tag; int fa,son[2],v; par mx; } t[maxn*11];

int dir(int o) {
	return t[t[o].fa].son[1]==o?1:
		   t[t[o].fa].son[0]==o?0:-1;
}
void add(int o,int f,int d) {
	if(o) t[o].fa=f;
	if(~d && f) t[f].son[d]=o;
}
void pushUp(int o) {
	t[o].mx = make_pair(t[o].v,o);
	t[o].mx = (t[o].mx<t[t[o].son[0]].mx? t[t[o].son[0]].mx: t[o].mx);
	t[o].mx = (t[o].mx<t[t[o].son[1]].mx? t[t[o].son[1]].mx: t[o].mx);
}
void rev(int o) {
	t[o].tag ^= 1;
	swap(t[o].son[0],t[o].son[1]);
}
void pushDown(int o) {
	if(!t[o].tag) return; t[o].tag=0;
	rev(t[o].son[0]), rev(t[o].son[1]);
}
void rotate(int o) {
	int f=t[o].fa, ff=t[f].fa;
	int d=dir(o), fd=dir(f);
	add(t[o].son[d^1],f,d);
	add(f,o,d^1), add(o,ff,fd);
	pushUp(f), pushUp(o);
}
void pushAll(int o) {
	static int stk[maxn*11], tp;
	stk[tp=1] = o;
	while(~dir(o)) stk[++tp] = (o=t[o].fa);
	while(pushDown(stk[tp--]), tp);
}
void splay(int o) {
	pushAll(o);
	for(int f; f=t[o].fa, ~dir(o); rotate(o))
		if(~dir(f)) rotate(dir(f)==dir(o)?f:o);
}
void access(int o) {
	for(int ch=0; o; o=t[ch=o].fa)
		splay(o), t[o].son[1]=ch, pushUp(o);
}
void makeRoot(int o) { access(o), splay(o), rev(o); }
void split(int x,int y) { makeRoot(x), access(y), splay(x); }
void link(int x,int y) { makeRoot(x), t[x].fa=y; }
void cut(int x,int y) { split(x,y), t[x].son[1]=t[y].fa=0, pushUp(x); }

}

namespace UFS {

int Stk[maxn*10],s_tp,f[maxn],sz[maxn];

int fin(int x) { return x==f[x]?x:fin(f[x]); }
void merge(int x,int y) {
	x = fin(x), y = fin(y); 
	if(sz[x]<sz[y]) swap(x,y);
	Stk[++s_tp] = y; f[y]=x, sz[x]+=sz[y];
}
void initialize() {
	for(int i=1;i<=idx;++i) f[i]=i, sz[i]=1;
}
void goBack(int goal) {
	while(s_tp^goal) {
		int u = Stk[s_tp--];
		sz[f[u]] -= sz[u], f[u]=u;
	}
}
	
}

void link(int x,bool opt=0) {
	cur += E[x].w; lct::t[x+idx].v=E[x].w; 
	if(!opt) rec[++now]=x;
	lct::link(x+idx,E[x].u), lct::link(x+idx,E[x].v);
}
void cut(int x,bool opt=0) {
	cur -= E[x].w; if(!opt) rec[++now]=-x;
	lct::cut(x+idx,E[x].u), lct::cut(x+idx,E[x].v);
}
void goBack(int goal,int Goal) {
	UFS::goBack(goal);
	while(Goal^now) {
		int x = rec[now--];
		if(x>0) cut(x,1);
		else link(-x,1);
	}
}

bool exi[maxn<<2];
void ins(int o,int l,int r) {
	exi[o] = true;
	if(l==r) return; int mid = l+r>>1;
	if(T<=mid) ins(o<<1,l,mid);
	else ins(o<<1|1,mid+1,r);
}
void ins(int o,int l,int r,int L,int R,int p) {
	if(l>=L && r<=R) return g[o].emplace_back(p), void();
	int mid = l+r>>1; if(L<=mid) ins(o<<1,l,mid,L,R,p);
	if(R>mid) ins(o<<1|1,mid+1,r,L,R,p);
}
void dicon(int o,int l,int r) {
	if(!exi[o]) return;
	int rest = UFS::s_tp, mid = l+r>>1, Rest = now;
	for(const auto& ID:g[o]) {
		int u=E[ID].u, v=E[ID].v; bool ban=0;
		if(UFS::fin(u)==UFS::fin(v)) {
			lct::split(u,v); int id=lct::t[u].mx.second;
			if(E[ID].w<lct::t[id].v) cut(id-idx);
			else ban = true;
		} else UFS::merge(u,v);
		if(!ban) link(ID);
	}
	if(l==r) return ans[l]=cur, goBack(rest,Rest), void();
	dicon(o<<1,l,mid), dicon(o<<1|1,mid+1,r);
	goBack(rest,Rest);
}

void ins(int o,bool opt=0) {
	if(!reID.count(o)) reID[o] = ++idx;
	o = reID[o];
	if(opt) 
		for(int i=R-1, lim=min(k-1,R-L), w; R-i<=lim; --i)
			w = random_Generator::getVal(),
			e[o].emplace_back(edge(++cnt,T)), E[cnt]=(Edge){o,reID[i],w},
			e[reID[i]].emplace_back(edge(cnt,T));
	else
		for(int i=L+1, lim=min(k-1,R-L), w; i-L<=lim; ++i)
			w = random_Generator::getVal(),
			e[o].emplace_back(edge(++cnt,T)), E[cnt]=(Edge){o,reID[i],w},
			e[reID[i]].emplace_back(edge(cnt,T));
}
void del(int o) {
	o = reID[o];
	for(const auto& to:e[o]) if(!vis[to.id]) 
		ins(vis[to.id]=1,1,n,to.t,T-1,to.id);
	e[o].clear(); // important!!!
}

int main() {
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	memset(ans,-1,sizeof ans);
	SEED=read(9), k=read(9), n=read(9);
	random_Generator::initialize(SEED);
	reID.insert(make_pair(0,idx=1));
	for(T=1;T<=n;++T) {
		int opt=read(9);
		if(opt==1) del(L++);
		else if(opt==2) del(R--);
		else if(opt==3) ins(--L);
		else if(opt==4) ins(++R,1);
		else ins(1,1,n); 
	}
	for(int i=1;i<=idx;++i) if(!e[i].empty()) 
		for(const auto& to:e[i]) if(!vis[to.id]) 
			ins(vis[to.id]=1,1,n,to.t,n,to.id);
	UFS::initialize();
	dicon(1,1,n);
	for(int i=1;i<=n;++i) if(~ans[i]) print(ans[i],'\n');
	return 0;
}

标签:mathbb,12,Contest,int,maxn,rm,2022.4,mex,dp
来源: https://www.cnblogs.com/AWhiteWall/p/14877024.html