考场

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. 【LeetCode】81. 搜索旋转排序数组 II

    81. 搜索旋转排序数组 II 知识点:数组,二分查找: 题目描述 已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同. 在传递给函数之前,nums 在预先未知的某个下标 k(0 ...

  2. GooseFS助力大数据业务数倍提升计算能力

    前言 GooseFS是由腾讯云推出的一款分布式缓存方案,主要针对包括需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. GooseFS 基于开源大数据缓存方案 Alluxi ...

  3. 【Python机器学习实战】感知机和支持向量机学习笔记(三)之SVM的实现

    前面已经对感知机和SVM进行了简要的概述,本节是SVM算法的实现过程用于辅助理解SVM算法的具体内容,然后借助sklearn对SVM工具包进行实现. SVM算法的核心是SMO算法的实现,首先对SMO算 ...

  4. Go语言笔记[实现一个Web框架实战]——EzWeb框架(一)

    Go语言笔记[实现一个Web框架实战]--EzWeb框架(一) 一.Golang中的net/http标准库如何处理一个请求 func main() { http.HandleFunc("/& ...

  5. Socket通信-客户端

    WSADATA wsd; SOCKET sHost; SOCKADDR_IN servAddr; if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) retu ...

  6. Spring学习04(使用注解开发)

    7.使用注解开发 说明:在spring4之后,想要使用注解形式,必须得要引入aop的包. 在配置文件当中,还得要引入一个context约束 <?xml version="1.0&quo ...

  7. 安鸾CTF Writeup SSRF02

    SSRF02 题目链接:http://www.whalwl.host:8090/ 看到题目,以为是SSRF 获取内网信息, SFTP FTP Dict gopher TFTP file ldap 协议 ...

  8. DVWA(九):File Upload 全等级文件上传

    File Upload 文件上传,通常是由于对上传文件的类型没有进行严格的过滤.限制造成的,一般思路是 通过上传木马获取服务器的webshell(通过网络端口对网站服务器某种程度上的操作权限 也叫网站 ...

  9. C#:[StructLayout(LayoutKind.Sequential)]

    参考网址: https://blog.csdn.net/hongkonglife/article/details/23422857 结构体是由若干成员组成的.布局有两种1.Sequential,顺序布 ...

  10. [ASP.NET MVC]@Html.ActionLik重载

    一 Html.ActionLink("linkText","actionName") 该重载的第一个参数是该链接要显示的文字,第二个参数是对应的控制器的方法, ...