20220616

时间很不够用啊,以后争取有比赛的时候发博,没比赛的时候更博


  • rk13/51, 0+30+20=50
  • max: 100, 80, 20, 100+30+20=150

考得很差。
一开始 T1 读错题以为是萌萌贪心,读对后一脸不可做直接跳了,结果 T1 是签到
T2 不可持久化会 ODT,磨磨蹭蹭不想写,最后没时间调了
T3 搜索写挂、构造方案假了,赛后很快发现,赛时干嘛去了呢?没拍就没有脑子吗?


小学生物理题

检查若干次后可以确定断掉的导线在一个区间内,考虑区间 DP。设 \(f[l,r,0/1]\) 表示答案在区间 \((l,r)\) 中,当前在 \(l/r\) 的答案。对 \(s\) 做前缀和后 \(f[l,r,0]=\min_{i=l+1}^{r-1}\{\max(f[l,i,1],f[i,r,0])+s_{i}+d_{i}\}-s_{l}\)

\(l\) 一定时 \(f[l,r]\) 单调,因此 \(\exists p\),对于 \(i<p,f[l,i,1]\le f[i,r,0];i\ge p,f[l,i,1]>f[i,r,0]\),这样就拆开了 \(\max\)
对于 \(f[l,i,1]\)\(i\) 是单调向右的,可以用一个单调队列维护
对于 \(f[i,r,0]\)\(l\) 向左时 \(i\) 也单调向左,可以对每个 \(r\) 用一个单调队列维护

注意一些边界。时空复杂度 \(O(n^{2})\)

code
const int N = 3e3+5;
const LL infll = 0x3f3f3f3f3f3f3f3f;
int n,a[N],b[N];
LL s[N],f[N][N],g[N][N];

struct {
	int l=1,r,a[N]; LL b[N];
	void clr() { l = 1, r = 0; }
	void push(int x,LL y) {
		while( l <= r && y <= b[r] ) --r;
		a[++r] = x, b[r] = y;
	}
	LL fro(int lim) {
		while( l<=r && a[l] < lim ) ++l;
		return l<=r ? b[l] : infll;
	}
} qf1[N],qg1[N],qf2,qg2;

signed main() { freopen("physics.in","r",stdin); freopen("physics.out","w",stdout);
	io>>n; For(i,2,n) io>>s[i], s[i] += s[i-1]; s[n+1] = s[n];
	For(i,1,n) io>>a[i]; For(i,0,n) io>>b[i];
	For(i,0,n) f[i][i+1] = g[i][i+1] = b[i];
	rFor(l,n,0) {
		qf2.clr(), qg2.clr();
		auto add=[](int l,int r) {
			qf1[r].push(-l,f[l][r]+s[l]+a[l]), qg1[r].push(-l,f[l][r]-s[l]+a[l]),
			qf2.push(r,g[l][r]+s[r]+a[r]), qg2.push(r,g[l][r]-s[r]+a[r]);
		};
		add(l,l+1);
		For(r,l+2,n+1, p = l+1) {
			while( p <= r-1 && g[l][p] <= f[p][r] ) ++p;
			f[l][r] = min(qf1[r].fro(-(p-1)),qf2.fro(p)) - s[l],
			g[l][r] = min(qg1[r].fro(-(p-1)),qg2.fro(p)) + s[r];
			add(l,r);
		}
	}
	io<<f[0][n+1];
	return 0;
}

数轴变换

考虑用括号表示黑色连续段(不要求相互不交),使用可持久化平衡树分别维护左/右括号的位置,操作 1,2,4,5 均平凡
操作 3 可能会使一些连续段被分开。考虑在操作区间的前后插入若干 )...)(...( 来使得没有段跨过操作区间,然后直接翻转即可

一个细节是询问只需要判断前面的左括号数是否 \(\ne\) 右括号数,且差 \(\le n\),因此可以使用 unsigned 来保存括号数

code
const int N = 2e5+5;
int m,ans;

#define ls(u) t[u].ch[0]
#define rs(u) t[u].ch[1]
int ind,T,t1[N],t2[N];
struct { int ch[2],siz,t; LL val,add; unsigned cnt,sum; bool rev; } t[N*100];
int node(LL p,unsigned x) { return t[++ind] = {0,0,1,T,p,0,x,x,0}, ind; }
int node(int u) { return t[u].t==T ? u : (t[++ind] = t[u], t[ind].t = T, ind); }
void up(int u) {
	t[u].siz = t[ls(u)].siz + 1 + t[rs(u)].siz,
	t[u].sum = t[ls(u)].sum + t[u].cnt + t[rs(u)].sum;
}
void down(int u,bool x,LL y) {
	if( x ) t[u].val *= -1, t[u].add *= -1, t[u].rev ^= 1, swap(ls(u),rs(u));
	if( y ) t[u].val += y, t[u].add += y;
}
void down(int u) { if( t[u].rev || t[u].add ) {
	if( ls(u) ) down(ls(u)=node(ls(u)),t[u].rev,t[u].add);
	if( rs(u) ) down(rs(u)=node(rs(u)),t[u].rev,t[u].add);
	t[u].rev = t[u].add = 0;
}}
void split(int u,LL x,int &l,int &r) {
	if( !u ) return l = r = 0, void();
	down(u=node(u));
	if( t[u].val <= x ) l = u, split(rs(u),x,rs(l),r), up(l);
	else r = u, split(ls(u),x,l,ls(r)), up(r);
}
int merge(int l,int r) {
	if( !l || !r ) return l | r;
	if( rnd(1,t[l].siz+t[r].siz) <= t[l].siz )
		return down(l), rs(l) = merge(rs(l),r), up(l), l;
	return down(r), ls(r) = merge(l,ls(r)), up(r), r;
}
void ins(int &rt,LL p,unsigned x) {
	int l,r; split(rt,p,l,r);
	rt = merge(l,merge(node(p,x),r));
}
unsigned qry(int &rt,LL x) {
	int l,r; split(rt,x,l,r);
	unsigned res = t[l].sum;
	return rt = merge(l,r), res;
}
void dbg(int u) {
	down(u);
	if( ls(u) ) dbg(ls(u));
	cerr<<t[u].val<<' '<<t[u].cnt<<endl;
	if( rs(u) ) dbg(rs(u));
}

signed main() { freopen("trans.in","r",stdin); freopen("trans.out","w",stdout);
	ios::sync_with_stdio(0);cin.tie(0);
	t1[0] = node(0,1), t2[0] = node(0,1);
	m=read(); For(i,1,m) {
		++T;
		auto rd=[]() { return read<LL>()^ans; };
		int op=read(); LL x=rd(),y;
		if( op == 4 ) t1[i] = t1[x], t2[i] = t2[x];
		else {
			t1[i] = node(t1[i-1]), t2[i] = node(t2[i-1]);
			if( op == 1 ) ins(t1[i],x,1), ins(t2[i],x,1);
			else if( op == 2 ) down(t1[i],0,-x), down(t2[i],0,x);
			else if( op == 3 ) {
				y = rd();
				int a1,b1,c1,a2,b2,c2;
				split(t1[i],y,a1,c1), split(a1,x-1,a1,b1),
				split(t2[i],y,a2,c2), split(a2,x-1,a2,b2);
				if( unsigned s = t[a1].sum-t[a2].sum )
					b1 = merge(node(x,s),b1), a2 = merge(a2,node(x-1,s));
				if( unsigned s = t[c2].sum-t[c1].sum )
					c1 = merge(node(y+1,s),c1), b2 = merge(b2,node(y,s));
				down(b2,1,x+y), t1[i] = merge(a1,merge(b2,c1)),
				down(b1,1,x+y), t2[i] = merge(a2,merge(b1,c2));
			} else {
				if( qry(t1[i],x) != qry(t2[i],x-1) ) cout<<"Yes\n", ++ans;
				else cout<<"No\n";
			}
		}
//		cerr<<"i = "<<i<<":\n";
//		For(j,0,i)
//			cerr<<"t1["<<j<<"]:\n", dbg(node(t1[j])),
//			cerr<<"t2["<<j<<"]:\n", dbg(node(t2[j])), cerr<<endl;
	}
	cerr<<ind<<endl;
	return 0;
}

中学生物理题

先求出所有循环,比较好的做法是并查集

然后把循环看成点,镜子看成边建无向图(若镜子一侧没有循环则与虚点连边)。问题转化为给边四染色,使得除虚点外每个点所连每种颜色的边数相同且为偶数(自环算两条)
必要条件为除虚点外每个点的度数为 \(8\) 的倍数,构造说明这也是充分条件

考虑通过二染色两次来实现四染色。找一条从虚点开始的欧拉回路,把边分成第奇数条和第偶数条。对这两部分再做一次相同的构造即可
注意第二次构造时必须从虚点开始跑欧拉路。因为这个构造的原理是欧拉路中一定是进入某个点后立刻出来,这两条边一定被分到了两个集合中(自环无影响),但是这对起点是不成立的。对于虚点不在的连通块,可以随便跑,因为点的度数都是 \(4\) 的倍数

code
#define no io<<-1,exit(0)
const int N = 5e5+5;
int n,m,ind,x[N],y[N],vis[4][N];
char c[N];
Vi o,a[N*2],b[N*2],cir[N],in[N];
unordered_map<int,int> id[N*2];

auto lsh=[](int &x) { x = lwb(all(o),x)-o.begin()+1; };

bool dfs(int u,int d) {
	if( vis[d][u] == ind ) return ++m, 1;
	if( vis[d][u] ) return 0;
	int x = ::x[u], y = ::y[u];
	if( !d ) {
		auto i = upb(all(a[x]),y); if( i == a[x].end() ) return 0;
		y = *i;
	} else if( d == 1 ) {
		auto i = upb(all(b[y]),x); if( i == b[y].end() ) return 0;
		x = *i;
	} else if( d == 2 ) {
		auto i = lwb(all(a[x]),y); if( i == a[x].begin() ) return 0;
		y = *--i;
	} else {
		auto i = lwb(all(b[y]),x); if( i == b[y].begin() ) return 0;
		x = *--i;
	}
	int v = id[x][y];
	vis[d][u] = vis[d^2][v] = ind;
	if( dfs(v,c[v]=='\\'?3-d:d^1) ) return cir[m].pb(u), in[u].pb(m), 1;
	return 0;
}

struct Graph {
	static const int N = 1e6+5;
	int m=1,head[N],to[N],nxt[N],id[N];
	bitset<N> del,col;
	void adde(int i,int x,int y) {
		nxt[++m] = head[x], to[m] = y, head[x] = m;
		nxt[++m] = head[y], to[m] = x, head[y] = m;
		id[i] = m;
	}
	void dfs(int s) {
		static stack<Pii> stack;
		bool res=0;
		stack.emplace(s,0);
		while( sz(stack) ) {
			int u,pre; tie(u,pre) = stack.top();
			int &i = head[u];
			while( i && del[i] ) i = nxt[i];
			if( i ) del[i] = del[i^1] = 1, stack.emplace(to[i],i);
			else col[pre] = col[pre^1] = res, res ^= 1, stack.pop();
		}
	}
	void euler() { For(i,0,n) if( head[i] ) dfs(i); }
	bool qry(int i) { return col[id[i]]; }
} g,g1,g2;

signed main() { freopen("scisyhp.in","r",stdin); freopen("scisyhp.out","w",stdout);
	io>>n; For(i,1,n) io>>x[i]>>y[i]>>c[i], o.pb(x[i]), o.pb(y[i]);
	sort(all(o)), o.erase(unique(all(o)),o.end());
	For(i,1,n)
		lsh(x[i]), lsh(y[i]), id[x[i]][y[i]] = i,
		a[x[i]].pb(y[i]), b[y[i]].pb(x[i]);
	For(i,1,sz(o)) sort(all(a[i])), sort(all(b[i]));
	For(i,1,n) Rep(j,0,4) if( !vis[j][i] ) ++ind, dfs(i,j);
	For(i,1,m) if( sz(cir[i]) % 8 ) no;
//	For(i,1,m) { for(int j : cir[i]) cerr<<j<<' '; cerr<<endl; }
	For(i,1,n) {
		while( sz(in[i]) < 2 ) in[i].pb(0);
		g.adde(i,in[i][0],in[i][1]);
	} g.euler();
	For(i,1,n) (g.qry(i)?g1:g2).adde(i,in[i][0],in[i][1]);
//	cerr<<"g1:\n"; For(i,1,n) if( g.qry(i) )
//		cerr<<i<<"  "<<in[i][0]<<' '<<in[i][1]<<endl;
	g1.euler();
//	cerr<<"g2:\n"; For(i,1,n) if( !g.qry(i) )
//		cerr<<i<<"  "<<in[i][0]<<' '<<in[i][1]<<endl;
	g2.euler();
/*	For(i,1,m) {
		int cnt[5]={0};
		for(int j : cir[i]) ++cnt[g.qry(j) ? (g1.qry(j)?1:2) : (g2.qry(j)?3:4)];
		For(j,1,4) if( cnt[j] != sz(cir[i])/4 )
			cerr<<i<<": cnt["<<j<<"] = "<<cnt[j]<<endl;
	}*/
	For(i,1,n)
		if( g.qry(i) ) io<<(g1.qry(i)?1:2)<<' ';
		else io<<(g2.qry(i)?3:4)<<' ';
	return 0;
}
posted @ 2022-06-17 07:10  401rk8  阅读(54)  评论(0编辑  收藏  举报