考场

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. 租了一台华为云耀云服务器,却直接被封公网ip,而且是官方的bug导致!

    小弟在博客园也有十多个年头了,因为离开了.net圈子,所以很少发文,今天可算是被华为云气疯了.写下这篇文章,大家也要注意自查一下,避免无端端被封公网ip. 因为小弟创业公司业务发展,需要一个公网做宣传 ...

  2. Bugku-web-web8

    可以看到题目提示了一个txt的东西,猜测目录下会有flag.txt这个文件. 通过代码审计我们可以知道得到flag的条件,访问flag.txt得到一串字符. 那么payload就很好构造了,$f的值是 ...

  3. WPF按钮实现水波纹效果

    xaml代码如下 <Button x:Class="UI.btn.ZButton" xmlns="http://schemas.microsoft.com/winf ...

  4. MySQL-05-DDL/DCL/DML语句

    DDL数据定义语言 库定义 1 创建数据库 mysql> create database school; mysql> create schema sch; mysql> show ...

  5. Java Lambda 表达式源码分析

    基本概念 Lambda 表达式 函数式接口 方法引用 深入实现原理 字节码 为什么不使用匿名内部类? invokedynamic 总结 参考链接 GitHub 项目 Lambda 表达式是什么?JVM ...

  6. Beescms V4.0_R_20160525代码审计笔记

    写在前面 什么是报错注入?正常用户访问服务器发送id信息返回正确的id数据.报错注入是想办法构造语句,让错误信息中可以显示数据库的内容:如果能让错误信息中返回数据库中的内容,即实现SQL注入. 复现过 ...

  7. DFT、DTFT、DFS、FFT之间的关系

    DFT.DTFT.DFS.FFT.FT.FS之间的关系 FT和FS是研究连续信号的,在数字信号处理中不涉及. 主要是前四种的关系: DFT(Discrete Fourier Transform):离散 ...

  8. 《JERRY Hexo & GitHub 静态网站搭建说明》

    JERRY-Hexo-GitHub <JERRY Hexo & GitHub 静态网站搭建说明> 原创内容,转载请注明出处! 一.前言 1.1 什么是 Hexo? 一个基于 Nod ...

  9. asp.net core 中的路由

  10. 使用SuperSocket实现自定义协议C/S设计

    一.简介: 21世纪是出于互联网+的时代,许多传统行业和硬件挂钩的产业也逐步转向了系统集成智能化,简单来说就是需要软硬件的结合.这时,软硬件通讯便是这里面最主要的技术点,我们需要做到的是让硬件能够听懂 ...