考场

T1 这不裸的容斥

T2 这不裸的欧拉路,先从奇数度点开始走,走不了就传送

T3 什么玩意,暴力都不会

T4 点分树???

仔细想了一波,发现 T1 T2 都好做,T3 二分答案后可以暴力贪心,但不知道复杂度是啥,T4 点分治+暴力修改有 69pts

8.00 开 T1,先打了个暴力确定是简单环,然后开始写,一直 WA,写到 9.20 过了小样例,但大样例差 \(3\),仔细看了看是把一个 * inv2 写成了 / 2,改完开拍。然后开始修锅,补丁摞补丁,终于在 9.50 过拍,感觉很稳。

发现只剩 1.5h 了,迅速 rush 完 T2,又想了想 T3 还是不会,输出样例走人。10.20 开 T4,到 11.00 写完了点分治,斟酌了一下决定冲 sub3,11.10 过了小样例,但大样例 RE 了,原因不明。

11.15 开始交题,正好测完所有样例。

res

rk7 17+39+0+47

T1 还有一个地方是 / 2,小数据下没有取模,大样例模完是恰好偶数。

rk1 szs 100+7+80+87

rk2 ycx 61+30+0+26

rk8 陈天宇 29+40+0+13

总结

一个老问题:没想清楚就着急写,结果浪费了很多时间 debug+打补丁,而且还有可能打不全或发现算法假了。

T1 代码不难写,但考场上最开始写的漏洞百出,面向数据编程了好久;T4 从昨天下午 4 点改到今早 9 点(今天重构代码了),就是思路不清晰,算法都是假的,还一直调试。

这一点上 ycx 做到很好,他几乎没写过假做法,而且每次写题前都在草稿纸上列好了,不会出现写到一半发现有 bug 的情况,这就是为什么一起开始改,他昨晚 8 点就 A 了。

以后一定一定要想清楚,确定做法没错再写。

还有重构代码这件事,其实昨晚就有着想法了,因为看网上的题解和我写的非常不一样,但我本身非常排斥。我记得上一次重构还是在去年写一道单调队列的题,但事实上如果需要打补丁的地方很多,真的不如重构。一方面写过一遍,写第二遍不会很浪费时间,而且实现会更好;另一方面重写可以让整个思路/代码是连续且独立的,而不是在原来的思路/代码上改,容易受影响。

不管重不重构,果断一点,不要犹犹豫豫地浪费时间。

至于 T1 挂分,确实是活该。前面干过不少挤占检查时间 rush 题的事(交题前检查时间:20min->15min->5min->0),最后 20min 开始写线段树几乎是家常便饭,今天算是遭报应了。

T1 过了大样例的时候我还很高兴,感觉前天的组合没白学,现在看来是脑子和眼睛白长了。

T2 的欧拉路确实是不会,当时只记住了实现,没搞懂原理,只能是不断查漏补缺了。(怎么感觉这话以前写过)

最后一件事,思维太僵化。

通常情况下 DS 我都写的比较好,但这是基于背板和手速的。一旦遇上需要根据改动,代码不长但难调的题就爆毙了。暂时没什么好办法,只能多做题,积累经验了。

T4 的式子只想到暴力展开,没能从实际意义的角度去分析。

sol

这套题比较卡常,且 T1 T2 代码都是在考场代码上改的,比较难看。

T2 T3 T4 有不同的实现/做法,可以看这篇

Lighthouse

一张完全图不同 \(n\) 元环的数量为 \(\frac{(n-1)!}2\)

暴力枚举选的边容斥。注意细节:一个点度数 \(\neq2\) 就不合法;有环就不合法,但 \(n\) 元环合法;点不分前后,但链有。

code
const int N = 1e7+5, M = 25, mod = 1e9+7, inv2 = 5e8+4;
int n,m;
PII e[M]; int all,id[N],deg[N],fa[N];
LL ans,fac[N]; LL Pow(LL x,LL y=mod-2)
{ LL res=1; for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod; return res; }
void ckadd(LL &x,LL y) { x+=y; if(x>=mod)x-=mod; else if(x<0)x+=mod; } int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); } int count(int s) { int res=0; for(;s;s-=s&-s)++res; return res; }
bool cir(int s) {
if( count(s) != n ) return 0;
int res = 0;
For(i,0,m) if( (s >> i) & 1 )
fa[find(e[i].fi)] = find(e[i].se), ++deg[e[i].fi], ++deg[e[i].se];
For(i,1,n) {
res += fa[i]==i;
if( deg[i] != 2 ) res = N;
}
For(i,1,n) fa[i] = i, deg[i] = 0;
return res==1;
}
LL calc(int s) {
if( cir(s) ) return 1;
int n1 = 0, res = 0, cnt = 0;
For(i,0,m) if( (s >> i) & 1 ) {
id[++n1] = e[i].fi, id[++n1] = e[i].se;
++deg[e[i].fi], ++deg[e[i].se];
if( find(e[i].fi) == find(e[i].se) ) res = N;
fa[find(e[i].fi)] = find(e[i].se);
}
sort(id+1,id+n1+1), n1 = unique(id+1,id+n1+1)-id-1;
For(i,1,n1) ckmax(res,deg[id[i]]), cnt += fa[id[i]]==id[i];
For(i,1,n1) deg[id[i]] = 0, fa[id[i]] = id[i];
LL ans = res<=2 ? fac[n-n1+cnt-1]*inv2%mod*Pow(2,cnt)%mod : 0;
return ans;
} signed main() {
read(n,m); all = (1 << m--) - 1;
fac[0] = 1; For(i,1,n) fac[i] = fac[i-1] * i %mod;
For(i,1,n) fa[i] = i;
For(i,0,m) read(e[i].fi,e[i].se);
For(s,0,all) ckadd(ans,(count(s)&1?-1:1)*calc(s));
write(ans);
return iocl();
}

Miner

由于欧拉路的算法只能在合法的图上跑,因此需要先手动连边。

注意每个联通块有欧拉路就行了,因此可以有 \(\le2\) 个奇数度点。

code
const int N = 1e5+5;
int n,m,mm=1,head[N],to[N*4],w[N*4],nxt[N*4]; int s,n1,deg[N],fa[N],id[N];
bool vis[N*4];
int tp,rea,ans1; PII stk[N*4],ans[N*4]; void adde(int x,int y,int z)
{ to[++mm] = y, w[mm] = z, nxt[mm] = head[x], head[x] = mm; }
void link(int x,int y,int z) { adde(x,y,z), adde(y,x,z), ++deg[x], ++deg[y]; } int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); } void dfs(int u,int x=1) {
static int top; top=0; static PII stack[N*4];
stack[++top] = MP(x,u);
while( top ) {
u = stack[top].se; int i = head[u];
while( i && vis[i] ) i = nxt[i];
if( i ) {
head[u] = nxt[i], vis[i] = vis[i^1] = 1, --deg[u], --deg[to[i]];
stack[++top] = MP(w[i],to[i]);
} else {
if( ~stack[top].fi ) stk[++tp] = stack[top];
--top;
}
}
}
void print() { while( tp ) ans1 += stk[tp].fi, ans[++rea] = stk[tp--]; } signed main() {
read(n,m);
For(i,1,n) fa[i] = i;
For(i,1,m) {
int x,y; read(x,y);
link(x,y,0), fa[find(x)] = find(y);
}
For(i,1,n) if( deg[i] & 1 ) id[++n1] = i;
sort(id+1,id+n1+1,[](const int &x,const int &y){return find(x)<find(y);});
for(int i = 1, cnt = 1; i <= n1; ++i) {
if( find(id[i]) == find(id[i-1]) ) {
++cnt;
if( cnt > 2 && !(cnt & 1) ) link(id[i],id[i-1],1);
} else cnt = 1;
}
For(i,1,n) if( deg[i] & 1 ) {
if( !s ) s = i, dfs(s,-1);
else dfs(i);
print();
}
For(i,1,n) if( deg[i] ) {
if( !s ) s = i, dfs(s,-1);
else dfs(i);
print();
}
write(ans1), write(s);
For(i,1,rea) write(ans[i].fi,' '), write(ans[i].se);
return iocl();
}

Lyk Love painting

二分答案后 DP 检验,分画所占行数转移,sol 讲的比较清楚了

code
const int N = 1e5+5;
int n,m,a[2][N]; int lst[3][N],f[N];
LL l,r,mid,s[3][N]; bool check() {
For(k,0,2) for(int i = 0, j = 1; j <= n; ++j) {
while( s[k][j]-s[k][i] > mid ) ++i;
lst[k][j] = i;
}
f[0] = 0;
For(i,1,n) {
f[i] = f[lst[2][i]] + 1;
int j = i, k = i, s = 0;
while( s < m && (j || k) ) {
if( j > k ) j = lst[0][j];
else k = lst[1][k];
++s;
ckmin(f[i],f[max(j,k)]+s);
}
if( f[i] > m ) return 0;
}
return 1;
} signed main() {
read(n,m);
For(i,0,1) For(j,1,n) {
read(a[i][j]), s[i][j] = s[i][j-1] + a[i][j];
ckmax(l,(LL)a[i][j]), r += a[i][j];
}
For(i,1,n) s[2][i] = s[2][i-1] + a[0][i] + a[1][i];
while( l < r ) {
mid = l+r>>1;
check() ? r=mid : l=mid+1;
}
write(l);
return iocl();
}

Revive

设 \(P(u,v)\) 为 \(u\) 到 \(v\) 路径上的边集,答案就是

\[\sum_{1\le u<v\le n}(\sum_{e\in P(u,v)}w_e)%2
\]

拆开得到

\[\sum_{e\in E}w_e^2\times经过e的路径数+2\sum_{e_1,e_2\in E,e_1<e_2}w_{e_1}\times w_{e_2}\times同时经过e_1,e_2的路径数
\]

前一部分很好统计,后一部分可以在点分治时记录每个子树的 \(\sum siz\times w\) 计算,具体细节可以自己推移下。

实现上,这题与普通点分治有些不同。为了避免特判,分治中心与其子树的连边并不在分治中心出计算贡献,而是在其子树中;修改需要记录分治时每一层的信息,但权值在边上,因此把信息记录在边上更方便。

另外,二维数组把大的一维开在前面内存访问更连续(否则最后一个 sub 会 T)

code
const int N = 1e6+5, mod = 1e9+7;
int SUB,n,q,fa[N];
LL w[N]; int mm=3,rt,rtmx,head[N],to[N*2],nxt[N*2],siz0[N*2],
siz[N],siz1[N][17],f[N],g[N][17],top[N][17];
bool vis[N];
LL ans,sum[N],sub[N][17]; LL pw2(LL x) { return x*x%mod; }
void ckadd(LL &x,LL y) { x+=y; if(x>=mod)x-=mod; else if(x<0)x+=mod; } void adde(int x,int y) { to[++mm] = y, nxt[mm] = head[x], head[x] = mm; }
int dfs0(int u) {
int sz = 1;
for(int i = head[u], v; v = to[i], i; i = nxt[i]) if( v != fa[u] ) {
siz0[i] = dfs0(v), siz0[i^1] = n-siz0[i], sz += siz0[i];
ckadd(ans,pw2(w[v])*siz0[i]%mod*siz0[i^1]%mod);
}
return sz;
} void findrt(int u,int fa) {
int mx = 0; siz[u] = 1;
for(int i = head[u], v; v = to[i], i; i = nxt[i]) if( !vis[v] && v != fa )
findrt(v,u), siz[u] += siz[v], ckmax(mx,siz[v]);
ckmax(mx,siz[0]-siz[u]);
if( mx < rtmx ) rtmx = mx, rt = u;
}
void dfs(int u,int pre,int d,int t) {
int e = pre>>1;
f[e] = d, g[e][d] = rt, top[e][d] = t, siz1[e][d] = siz0[pre];
ckadd(sub[t][d],siz1[e][d]*w[e]%mod);
if( vis[u] ) return;
siz[u] = 1;
for(int i = head[u], v; v = to[i], i; i = nxt[i]) if( (i ^ pre^1) ) {
dfs(v,i,d,t);
if( !vis[v] ) siz[u] += siz[v];
}
}
void work(int u,int d) {
vis[u] = 1;
for(int i = head[u], v; v = to[i], i; i = nxt[i])
dfs(v,i,d,i>>1),
ckadd(ans,2*sub[i>>1][d]*sum[u]%mod), ckadd(sum[u],sub[i>>1][d]);
for(int i = head[u], v; v = to[i], i; i = nxt[i]) if( !vis[v] )
siz[rt=0] = rtmx = siz[v], findrt(v,u), work(rt,d+1);
} signed main() {
read(SUB,n,q);
For(i,2,n) { read(fa[i],w[i]); adde(fa[i],i), adde(i,fa[i]); }
dfs0(1);
siz[0] = rtmx = n, findrt(1,0), work(rt,1);
write(ans);
while( q-- ) {
int u; LL x; read(u,x);
rFor(i,f[u],1) {
rt = g[u][i]; LL del = siz1[u][i] * x %mod;
ckadd(ans,2*(sum[rt]-sub[top[u][i]][i])*del%mod);
ckadd(sub[top[u][i]][i],del), ckadd(sum[rt],del);
}
ckadd(ans,(2*w[u]*x+pw2(x))%mod*siz0[u<<1]%mod*siz0[u<<1|1]%mod);
ckadd(w[u],x);
write(ans);
}
return iocl();
}

20210826 Lighthouse,Miner,Lyk Love painting,Revive的更多相关文章

  1. Lyk Love painting/convex hull/mumsic

    这场比赛真的是...打的好颓废啊... 所有题面的传送门 T1 分析: 我们发现 二分答案 + \(n^3\) \(dp\) 判断可行性 可以拿 60 分(于是就写好了啊!) 然后我们发现上面的 \( ...

  2. 复习&反思

    阴间题目 半夜 糖果 Cicada 与排序 排列 Cover 玩具 夜莺与玫瑰 God Knows 简单的填数 反思 20210826 Lighthouse,Miner,Lyk Love painti ...

  3. noip模拟48

    A. Lighthouse 很明显的容斥题,组合式与上上场 \(t2\) 一模一样 注意判环时长度为 \(n\) 的环是合法的 B. Miner 题意实际上是要求偶拉路 对于一个有多个奇数点的联通块, ...

  4. 2019.03.15 ZJOI2019模拟赛 解题报告

    得分: \(20+45+15=80\)(三题暴力全写挂...) \(T1\):Lyk Love painting 首先,不难想到二分答案然后\(DP\)验证. 设当前需验证的答案为\(x\),则一个暴 ...

  5. Qt Lighthouse学习(二),就是QPA(Qt Platform Abstraction) 项目的名字

    上一次关注Qt Lighthouse是在6月初,可是现在都8月底了.时间真快... Lighthouse 是 QPA(Qt Platform Abstraction) 项目的名字,它使得将Qt移植到新 ...

  6. 清华学堂 LightHouse

    灯塔(LightHouse) Description As shown in the following figure, If another lighthouse is in gray area, ...

  7. 新上市Lighthouse专用芯片TS3633规格介绍

    背景介绍 Valve 有远大的愿景.它决心要把 SteamVR 追踪系统推向世界,从虚拟现实里的空间定位,到机器人领域,Valve 想为各种环境下的跟踪应用提供支持. 上个月,Valve 方面宣布会把 ...

  8. 51nod lyk与gcd

    1678 lyk与gcd 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 这天,lyk又和gcd杠上了.它拥有一个n个数的数列,它想实现两种操作. 1:将  ai  ...

  9. CF448C Painting Fence (分治递归)

    Codeforces Round #256 (Div. 2) C C. Painting Fence time limit per test 1 second memory limit per tes ...

随机推荐

  1. 安装npm后,nrm ls报错问题

    一.nrm : 无法加载文件 E:\nodejs\nrm.ps1,因为在此系统上禁止运行脚本.有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135 ...

  2. helm离线安装helm-push插件

    helm-push版本:helm-push_0.9.0_linux_amd64 helm-push安装包 百度云: 链接:  helm-push_0.9.0_linux_amd64  提取码: 26b ...

  3. JAVA集合类概览

    带着问题来阅读 1.Java有哪些集合 2.不同集合的应用场景分别是哪些 3.哪些实现类是线程安全的 4.为什么Java集合不能存放基本类型 5.集合的fail-fast和fail-safe是什么 J ...

  4. 揭秘阿里云 RTS SDK 是如何实现直播降低延迟和卡顿

    作者:予涛 途坦 这个夏天,没什么能够比一场酣畅淋漓的奥运比赛来的过瘾.但是,在视频平台直播观看比赛也有痛点:"卡顿" 和 "延时".受限于不同地域.复杂的网络 ...

  5. 第2篇-JVM虚拟机这样来调用Java主类的main()方法

    在前一篇 第1篇-关于JVM运行时,开篇说的简单些 中介绍了call_static().call_virtual()等函数的作用,这些函数会调用JavaCalls::call()函数.我们看Java类 ...

  6. 为VIM添加Python扩展

    VIM的自带的脚本功能很强,但只能用在VIM自己上,如果让它支持Python脚本,那简直就无敌了,这个想法当然不是我想出来的,应该说英雄所见略同,于是乎vim7.2就内建了对python2.4的支持, ...

  7. MIT Scheme Development on Ubuntu

    sudo apt-get mit-scheme; run "scheme" then you enter the command line scheme repl; sudo ap ...

  8. PTA 朋友圈 (25 分) 代码详解 (并查集)

    1.题目要求: 某学校有N个学生,形成M个俱乐部.每个俱乐部里的学生有着一定相似的兴趣爱好,形成一个朋友圈.一个学生可以同时属于若干个不同的俱乐部.根据"我的朋友的朋友也是我的朋友" ...

  9. SpringBoot 整合缓存Cacheable实战详细使用

    前言 我知道在接口api项目中,频繁的调用接口获取数据,查询数据库是非常耗费资源的,于是就有了缓存技术,可以把一些不常更新,或者经常使用的数据,缓存起来,然后下次再请求时候,就直接从缓存中获取,不需要 ...

  10. CAS 5.3使用MySQL数据库验证

    一.本例环境说明 JDK 1.8 CAS 5.3 apache-maven-3.6.0 mysql-5.6.32 二.CAS 5.3基础环境搭建与验证 需要按照<CAS 5.3服务器搭建> ...