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;
}