7.14考试总结(NOIP模拟15)[夜莺与玫瑰·影子·玫瑰花精]
梦总是有会醒来的时候,不会醒的梦总有一天会变成悲伤。
前言
这次考试的思维含量有一点大(此时距离考试还有 7min 而我的总结还没写完。。)
但是对于以前的考试来讲还是有所进步的,毕竟在考试的时候还是第一次尝试着自己推柿子,最后也是成功的推出部分分的柿子。。
唯一遗憾的一点就是在 wzr 的领导下,我在 256MB 的内存下开了 \(10^4\times 10^4\) 的 long long 数组。
然后,就 MLE 0pts 了,我的 35 分就。。。(现在距离所谓的考试还有 2min ,但是考试突然没了)
再然后又说 14:40 开始考。。。起起伏伏。。。
对于第三题的话,裸的暴力,处理之后直接 sort 就可以搞到 60pts ,但是我一想到 sort 的复杂度就直接开了一个数组,手动一个一个按顺序插入,最后弄巧成拙,喜提 0pts。
虽然现在正在考试中,但这并不影响我写之前的考试总结,毕竟仅剩下 7min 了,我对于别的题也没有什么好的想法。
T1 夜莺与玫瑰
解题思路
对于 60pts 来说,显然的是要一个对于每一次询问 \(\mathcal{{O}}(n^2)\) 查询的办法。
于是我苦死冥想了整整 100min 想到了这个部分分。
(第一次隔天写文章。。),对于每一种线的最短线段一定会满足 \(\gcd(i-1,j-1)=1\) 。
在下面计算以及说明的时候为了方便,我们把所有的初始变量都减去一个 1 ,所以关于下面的说明可能会口胡多或者少一个 1 读者请意会一下(逃。
然后在 \((n,m)\) 的区间内,对于最短的线段(算上重复的)一共会有 \((n-i)\times (m-j)\) 条。
但是通过画图就可以发现 重复的就会有 \((n-2\times i)\times (m-2\times j)\) 条。
也就是下面的柿子:
\]
对于这个柿子维护二维前缀和。
第一个前缀和计算范围内的 \(\gcd\) 的数量,可以理解为从某一点出发的最短线段的个数。
然后在此基础上维护一个二维前缀和 \(pre_{n,m}=[\gcd(i,j)=1]((n-i)\times(m-j)\)。
然后我们尝试把这个柿子运用到之前的柿子上发现, 其实:
\]
接下来就可以直接套用公式并且对于奇数的情况进行处理就好了。
code
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e4+10,M=4e3+10,mod=1073741824;
int T,n,m,f[M][M],vis[M][M],pre[M][M];
struct Node
{
int x,y;
}q[N];
int Gcd(int x,int y)
{
if(!y) return x;
return Gcd(y,x%y);
}
void Init()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
vis[i][j]=(Gcd(i,j)==1);
vis[i][j]+=vis[i][j-1]+vis[i-1][j]-vis[i-1][j-1];
pre[i][j]=vis[i][j]+pre[i][j-1]+pre[i-1][j]-pre[i-1][j-1];
}
}
int solve(int x,int y)
{
int ans=0,mix=x/2,miy=y/2;
ans=pre[x-1][y-1];
ans=(ans+(4ll*mod-4*pre[mix-1][miy-1]))%mod;
if(x&1) for(int i=1;i<=miy;i++) ans=(ans+1ll*(2ll*mod-2ll*vis[mix][i-1]))%mod;
if(y&1) for(int i=1;i<=mix;i++) ans=(ans+1ll*(2ll*mod-2ll*vis[i-1][miy]))%mod;
if(x&1 && y&1) ans=(ans+1ll*(mod-vis[mix][miy]))%mod;
return (ans*2+x+y)%mod;
}
signed main()
{
T=read();
for(int i=1;i<=T;i++)
{
q[i].x=read();
q[i].y=read();
n=max(n,q[i].x);
m=max(m,q[i].y);
}
Init();
for(int i=1;i<=T;i++)
printf("%d\n",solve(q[i].x,q[i].y));
return 0;
}
T2 影子
解题思路
对于暴力算法可以分别以每个节点为根,分别查询这个节点到其他节点的距离以及最小值。
时间复杂度 \(\mathcal{O}(n^2)\) 空间复杂度 \(\mathcal{O}(n)\)
然后在考场上我搞了一个 \(n^2\) 的复杂度,再然后就 MLE 0pts,痛失 35pts(\(code\)) 。
正解是首先对于所有的节点按节点值从大到小进行排序(这样在搞的时候就不用考虑节点权值的关系了),然后把当前集合中的最长路的长度和两个端点用冰茶几维护。
用冰茶几合并这个节点以及与他有连边的节点所在的联通块。
维护的时候主要分为两大种情况:
原来的两个联通块分别的长度
由两个最长路的两个端点分别连接而成,共有 4 种。
每次冰茶几维护直接用两种值的乘积,更新既可,代码实现不算太难。。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e5+10,M=2e4,INF=1e9;
int n,m,T,ans,tim,fat[N],dep[N],son[N],siz[N],dfn[N],fa[N],topp[N],dis[N],clo[N];
int tot,head[N<<1],nxt[N<<1],ver[N<<1],edge[N<<1];
struct Node
{
int id,val;
}s[N];
struct Road
{
int l,r,len;
void clear()
{
l=r=len=0;
}
}pat[N],dist[10];
void add_edge(int x,int y,int val)
{
ver[++tot]=y;
edge[tot]=val;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs1(int x)
{
pat[x].l=pat[x].r=x;
siz[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(siz[to]) continue ;
dis[to]=dis[x]+edge[i];
dep[to]=dep[x]+1;
fat[to]=x;
dfs1(to);
siz[x]+=siz[to];
if(siz[to]>siz[son[x]])
son[x]=to;
}
}
void dfs2(int x,int tp)
{
topp[x]=tp;
dfn[x]=++tim;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i;i=nxt[i])
if(!dfn[ver[i]])
dfs2(ver[i],ver[i]);
}
int LCA(int x,int y)
{
if(!x||!y) return 0;
if(x==y) return x;
while(topp[x]^topp[y])
{
if(dep[topp[x]]<dep[topp[y]])
swap(x,y);
x=fat[topp[x]];
}
if(dep[x]>dep[y])
swap(x,y);
return x;
}
bool comp(Node x,Node y)
{
return x.val>y.val;
}
int find(int x)
{
if(fa[x]==x) return fa[x];
return fa[x]=find(fa[x]);
}
int Dist(int x,int y)
{
return dis[x]+dis[y]-2*dis[LCA(x,y)];
}
bool cmp(Road x,Road y)
{
return x.len>y.len;
}
void merge(int x,int y)
{
int minn=clo[x];
x=fa[find(x)];
y=fa[find(y)];
dist[1]=pat[x];
dist[2]=pat[y];
dist[3]=(Road){pat[x].l,pat[y].l,Dist(pat[x].l,pat[y].l)};
dist[4]=(Road){pat[x].l,pat[y].r,Dist(pat[x].l,pat[y].r)};
dist[5]=(Road){pat[x].r,pat[y].l,Dist(pat[x].r,pat[y].l)};
dist[6]=(Road){pat[x].r,pat[y].r,Dist(pat[x].r,pat[y].r)};
sort(dist+1,dist+7,cmp);
pat[x]=dist[1];
fa[y]=x;
ans=max(ans,dist[1].len*minn);
}
void solve(int x)
{
for(int i=head[x];i;i=nxt[i])
if(clo[ver[i]]>=clo[x])
merge(x,ver[i]);
}
void dfs3(int x,int fro)
{
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i];
if(to==fro) continue ;
dfs3(to,x);
}
dis[x]=dep[x]=dfn[x]=siz[x]=son[x]=topp[x]=head[x]=fa[x]=fat[x]=clo[x]=0;
pat[x].clear();
}
void work()
{
n=read();
for(int i=1;i<=n;i++)
{
clo[i]=read();
s[i]=(Node){i,clo[i]};
}
for(int i=1,x,y,val;i<n;i++)
{
x=read();
y=read();
val=read();
add_edge(x,y,val);
add_edge(y,x,val);
}
for(int i=1;i<=n;i++)
fa[i]=i;
sort(s+1,s+n+1,comp);
dfs1(1);
dfs2(1,1);
for(int i=1;i<=n;i++)
solve(s[i].id);
printf("%lld\n",ans);
dfs3(1,0);
tot=tim=ans=0;
}
signed main()
{
T=read();
while(T--) work();
return 0;
}
T3 玫瑰花精
解题思路
有一点像之前做过的 旅馆
,但是不完全一样。
用线段树维护序列,主要维护 7 个值:lmx,ll,rr,rmx,llen,rlen,len
主要分为三个区间:
与整个区间的左边界相连的最长长度(llen)以及端点(ll)
同样的与整个区间的右边界相连的最长长度(rlen)以及端点(rr)
整个区间内的除了左右两个区间的所有未入住的区间中最长的长度(len)以及左右端点(lmx,rmx)
然后在维护时候主要对于上面的三个区间进行查找。
然后就是单点修改,区间查询,在搞的时候比较考验码力,具体实现细节见代码:
code
#include<bits/stdc++.h>
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=2e5+10,M=1e6+10;
int n,m,s[M];
struct Segment_Tree
{
int lmx,ll,rr,rmx,llen,rlen,len;
}tre[N<<2];
inline void push_up(int x,int l,int r)
{
int mid=(l+r)>>1;
if( max( ((tre[rs].len+1)>>1),((tre[rs].llen+tre[ls].rlen+1)>>1) ) <= ((tre[ls].len+1)>>1) )
{
tre[x].len=tre[ls].len;
tre[x].lmx=tre[ls].lmx;
tre[x].rmx=tre[ls].rmx;
}
else if( max( ((tre[rs].len+1)>>1),((tre[ls].len+1)>>1) ) <= ((tre[rs].llen+tre[ls].rlen+1)>>1) )
{
tre[x].len=tre[rs].llen+tre[ls].rlen;
tre[x].lmx=tre[ls].rr;
tre[x].rmx=tre[rs].ll;
}
else if( max( ((tre[rs].llen+tre[ls].rlen+1)>>1),((tre[ls].len+1)>>1) ) <= ((tre[rs].len+1)>>1) )
{
tre[x].len=tre[rs].len;
tre[x].lmx=tre[rs].lmx;
tre[x].rmx=tre[rs].rmx;
}
tre[x].ll=tre[ls].ll;
tre[x].rr=tre[rs].rr;
tre[x].llen=tre[ls].llen;
tre[x].rlen=tre[rs].rlen;
if(tre[x].llen==mid-l+1)
{
tre[x].llen=mid-l+1+tre[rs].llen;
tre[x].ll=tre[rs].ll;
}
if(tre[x].rlen==r-mid)
{
tre[x].rlen=r-mid+tre[ls].rlen;
tre[x].rr=tre[ls].rr;
}
}
inline void build(int x,int l,int r)
{
tre[x].len=tre[x].llen=tre[x].rlen=r-l+1;//将可以入住的区间搞到最大
tre[x].lmx=tre[x].rr=l;//同时更新左右端点
tre[x].ll=tre[x].rmx=r;
if(l==r) return ;
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
inline void insert(int x,int l,int r,int pos)
{
if(l==r)
{
tre[x].len=tre[x].llen=tre[x].rlen=0;//标记入住
tre[x].lmx=tre[x].rr=pos+1;//三个区间错开
tre[x].ll=tre[x].rmx=pos-1;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos);//向下递归
else insert(rs,mid+1,r,pos);
push_up(x,l,r);
}
inline void delate(int x,int l,int r,int pos)
{
if(l==r)
{
tre[x].len=tre[x].llen=tre[x].rlen=1;
tre[x].lmx=tre[x].rr=tre[x].ll=tre[x].rmx=pos;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) delate(ls,l,mid,pos);//递归更新
else delate(rs,mid+1,r,pos);
push_up(x,l,r);
}
inline void solve1(int pos)
{
int ans=(tre[1].lmx+tre[1].rmx)>>1;
if(tre[1].llen>=(tre[1].len+1)/2) ans=1;//只剩下1节点或者左侧的长度大于中间最大的一半
else if(tre[1].rlen>(tre[1].len+1)/2) ans=n;//只剩下n节点或者右侧更优
s[pos]=ans;
insert(1,1,n,ans);//记录并更新
printf("%d\n",ans);
}
inline void solve2(int pos)
{
delate(1,1,n,s[pos]);
}
signed main()
{
n=read();
m=read();
build(1,1,n);
while(m--)
{
int opt,pos;
opt=read();
pos=read();
if(opt==1) solve1(pos);
else solve2(pos);
}
return 0;
}
7.14考试总结(NOIP模拟15)[夜莺与玫瑰·影子·玫瑰花精]的更多相关文章
- 2021.9.14考试总结[NOIP模拟53]
T1 ZYB和售货机 容易发现把每个物品都买成$1$是没有影响的. 然后考虑最后一个物品的方案,如果从$f_i$向$i$连边,发现每个点有一个出度多个入度,可以先默认每个物品都能买且最大获利,这样可以 ...
- 2021.8.14考试总结[NOIP模拟39]
T1 打地鼠 全场就俩人没切,还有一个是忘关$freopen$了. $code:$ 1 #include<bits/stdc++.h> 2 #define rin register sig ...
- [考试总结]noip模拟15
这次不咕了. 首先发现这套题目十分毒瘤, \(T1\) 就没有太大的思路. 结果最后也是暴力收场... 菜. \(T1\;60pts\) 暴力居然还是挺高的,\(T2\) 莽了一个随机化上去结果还是暴 ...
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...
- 5.22考试总结(NOIP模拟1)
5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...
- 2021.7.15考试总结[NOIP模拟16]
ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
- 2021.8.13考试总结[NOIP模拟38]
T1 a 入阵曲.枚举矩形上下界,之后从左到右扫一遍.用树状数组维护前缀和加特判可以$A$,更保险要脸的做法是双指针扫,因为前缀和单调不减. $code:$ 1 #include<bits/st ...
随机推荐
- docker 应用篇————具名挂载和匿名挂载[十三]
前言 简单整理一下具名挂载和匿名挂载. 正文 来看一下匿名挂载. 这里-v指定了容器内部的路径,但是没有指定容器外部的路径,那么挂载到了什么地方. 用inspect 查看一下. 挂载到这个位置了. 然 ...
- Typora图床配置(Typora+PicGo+Github)
Typora图床配置(Typora+PicGo+Github) 一.Github配置 登录github:https://github.com/ 新建仓库 生成私人令牌 Settings->Dev ...
- Swin Transformer安装记录(国内源,飞快)
0. 设备环境 ubuntu--20.10 GPU--3080 cuda--11.0 torch--1.7.0 mmcv--1.3.8 mmdetection--2.11.0 所有的git的项目,都可 ...
- WPF开发随笔收录-查看PDF文件
一.前言 在项目的开发过程中,涉及到查看服务器生成的pdf报告文件的查看,起初的方案是通过spire.pdf这个库来将pdf文件转换成图片,然后在进行查看.但是经常被吐槽预览不清晰,后面上网发现了一个 ...
- c#采用toml做配置文件的坑过
这几天在玩个程序,突然看到c#采用图toml文件,好用,直观,确实也简单. 不过...... github上示例写的 TOML to TomlTable TOML input file:v Enabl ...
- 力扣287(java&python)-寻找重复数(中等)
题目: 给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数. 假设 nums 只有 一个重复的整数 ,返回 这个重复的 ...
- 高效使用Java构建工具|Maven篇|云效工程师指北
简介:高效使用Java构建工具|Maven篇.众所周知,当前最主流的Java构建工具为Maven/Gradle/Bazel,针对每一个工具,我将分别从日常工作中常见的场景问题切入,例如依赖管理.构建 ...
- iLogtail使用入门-K8S环境日志采集到SLS
简介:iLogtail是阿里云中简单日志服务又名"SLS"的采集部分. 它用于收集遥测数据,例如日志.跟踪和指标,目前已经正式开源(https://github.com/alib ...
- WPF 基础 2D 图形学知识 判断点是否在线段上
在知道一个使用两个点表示的线段,和另一个点,求另一个点是否在线段上 本文算法属于通用的算法,可以在 WPF 和 UWP 和 Xamarin 等上运行,基本上所有的 .NET 平台都能执行 如下图,如果 ...
- Spark中的闭包引用和广播变量
闭包引用 概念 所有编程语言都有闭包的概念,闭包就是在一个函数中引用了函数外的变量. Spark中,普通的变量是在Driver程序中创建的,RDD的计算是在分布式集群中的task程序上进行的.因此,当 ...