20210826 Lighthouse,Miner,Lyk Love painting,Revive
考场
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 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的更多相关文章
- Lyk Love painting/convex hull/mumsic
这场比赛真的是...打的好颓废啊... 所有题面的传送门 T1 分析: 我们发现 二分答案 + \(n^3\) \(dp\) 判断可行性 可以拿 60 分(于是就写好了啊!) 然后我们发现上面的 \( ...
- 复习&反思
阴间题目 半夜 糖果 Cicada 与排序 排列 Cover 玩具 夜莺与玫瑰 God Knows 简单的填数 反思 20210826 Lighthouse,Miner,Lyk Love painti ...
- noip模拟48
A. Lighthouse 很明显的容斥题,组合式与上上场 \(t2\) 一模一样 注意判环时长度为 \(n\) 的环是合法的 B. Miner 题意实际上是要求偶拉路 对于一个有多个奇数点的联通块, ...
- 2019.03.15 ZJOI2019模拟赛 解题报告
得分: \(20+45+15=80\)(三题暴力全写挂...) \(T1\):Lyk Love painting 首先,不难想到二分答案然后\(DP\)验证. 设当前需验证的答案为\(x\),则一个暴 ...
- Qt Lighthouse学习(二),就是QPA(Qt Platform Abstraction) 项目的名字
上一次关注Qt Lighthouse是在6月初,可是现在都8月底了.时间真快... Lighthouse 是 QPA(Qt Platform Abstraction) 项目的名字,它使得将Qt移植到新 ...
- 清华学堂 LightHouse
灯塔(LightHouse) Description As shown in the following figure, If another lighthouse is in gray area, ...
- 新上市Lighthouse专用芯片TS3633规格介绍
背景介绍 Valve 有远大的愿景.它决心要把 SteamVR 追踪系统推向世界,从虚拟现实里的空间定位,到机器人领域,Valve 想为各种环境下的跟踪应用提供支持. 上个月,Valve 方面宣布会把 ...
- 51nod lyk与gcd
1678 lyk与gcd 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 这天,lyk又和gcd杠上了.它拥有一个n个数的数列,它想实现两种操作. 1:将 ai ...
- CF448C Painting Fence (分治递归)
Codeforces Round #256 (Div. 2) C C. Painting Fence time limit per test 1 second memory limit per tes ...
随机推荐
- 【LeetCode】81. 搜索旋转排序数组 II
81. 搜索旋转排序数组 II 知识点:数组,二分查找: 题目描述 已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同. 在传递给函数之前,nums 在预先未知的某个下标 k(0 ...
- GooseFS助力大数据业务数倍提升计算能力
前言 GooseFS是由腾讯云推出的一款分布式缓存方案,主要针对包括需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. GooseFS 基于开源大数据缓存方案 Alluxi ...
- 【Python机器学习实战】感知机和支持向量机学习笔记(三)之SVM的实现
前面已经对感知机和SVM进行了简要的概述,本节是SVM算法的实现过程用于辅助理解SVM算法的具体内容,然后借助sklearn对SVM工具包进行实现. SVM算法的核心是SMO算法的实现,首先对SMO算 ...
- Go语言笔记[实现一个Web框架实战]——EzWeb框架(一)
Go语言笔记[实现一个Web框架实战]--EzWeb框架(一) 一.Golang中的net/http标准库如何处理一个请求 func main() { http.HandleFunc("/& ...
- Socket通信-客户端
WSADATA wsd; SOCKET sHost; SOCKADDR_IN servAddr; if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) retu ...
- Spring学习04(使用注解开发)
7.使用注解开发 说明:在spring4之后,想要使用注解形式,必须得要引入aop的包. 在配置文件当中,还得要引入一个context约束 <?xml version="1.0&quo ...
- 安鸾CTF Writeup SSRF02
SSRF02 题目链接:http://www.whalwl.host:8090/ 看到题目,以为是SSRF 获取内网信息, SFTP FTP Dict gopher TFTP file ldap 协议 ...
- DVWA(九):File Upload 全等级文件上传
File Upload 文件上传,通常是由于对上传文件的类型没有进行严格的过滤.限制造成的,一般思路是 通过上传木马获取服务器的webshell(通过网络端口对网站服务器某种程度上的操作权限 也叫网站 ...
- C#:[StructLayout(LayoutKind.Sequential)]
参考网址: https://blog.csdn.net/hongkonglife/article/details/23422857 结构体是由若干成员组成的.布局有两种1.Sequential,顺序布 ...
- [ASP.NET MVC]@Html.ActionLik重载
一 Html.ActionLink("linkText","actionName") 该重载的第一个参数是该链接要显示的文字,第二个参数是对应的控制器的方法, ...