前言

CSP之后第一次模拟赛,感觉考的一般。

不得不吐槽多校联测 OJ 上的评测机是真的慢。。。

T1 树上的数

解题思路

感觉自己思维有些固化了,一看题目就感觉是线段树。

考完之后才想起来这玩意直接 DFS 一遍就行(大雾

然后就是卡常了,最后的结果就是时限 2s 的题本机 0.6s 才在OJ上过掉,我谔谔

果然迭代比递归快,所以直接 BFS 就可以减小常数了QAQ

code

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
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=5e6+10,base=19760817;
int n,m,A,B,X,Y,q,cnt,hd,tail,que[N];
int tot=1,head[N],ver[N],nxt[N];
bool vis[N];
ll ans;
inline void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
int main()
{
freopen("tree.in","r",stdin); freopen("tree.out","w",stdout);
cnt=n=read(); m=read(); A=read(); B=read(); add_edge(1,2);
for(int i=3,temp=1;i<=n;i++) temp=((1ll*temp*A+B)^base)%(i-1)+1,add_edge(temp,i);
q=read(); X=read(); Y=read();
for(int i=1;i<=m;i++)
{
if(i!=1) q=(((1ll*q*X+Y)^base)^(i<<1))%(n-1)+2;
hd=1;tail=0;if(!vis[q]) que[++tail]=q;
while(hd<=tail)
{
int x=que[hd++]; vis[x]=true; cnt--;
for(int j=head[x];j;j=nxt[j])
if(!vis[ver[j]]) que[++tail]=ver[j];
}
ans^=cnt;
}
printf("%lld",ans);
return 0;
}

T2 时代的眼泪

解题思路

大概有一点换根 DP 的思想吧,但是还是卡常,吐了。

比较直接的思路就是先计算出以 1 为根的答案,然后求出每个点相对于父亲节点变化的答案。

主席树和线段树合并的复杂度都是对的,但是都会被卡常!!!

因此需要树状数组,我们需要的无非就是一个全局的,一个以某棵子树为根的答案嘛。。

对于全局总体的直接一个桶+前缀和,然后对于某颗子树的就可以用搜索子树之前的信息减去搜索子树之后的信息,这样就可以用上小常数的树状数组了。。

实测差距还是很大的,以后还是要注意常数问题啊。。

code

被卡成 90pts 的线段树合并

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
#define ls tre[x].l
#define rs tre[x].r
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;
}
inline void write(int x)
{
return printf("%lld",x),void();
#define sta number
int sta[70],top=0; if(x<0) putchar('-'),x=~(x-1);
while(x) sta[++top]=x%10,x/=10; if(!top) sta[++top]=0;
while(top) putchar(sta[top--]+'0');
#undef sta
}
const int N=1e6+10;
int n,m,lim,all,cnt,root[N],s[N],fa[N];
int tot=1,head[N],ver[N<<1],nxt[N<<1];
struct Node{ll dat;int l,r;}tre[N*30];
vector<int> sta;
ll ans[N];
void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
int New()
{
if(!sta.size()) return ++all;
int x=sta[sta.size()-1];
tre[x].dat=ls=rs=0;
return sta.pop_back(),x;
}
#define push_up(x) tre[x].dat=tre[ls].dat+tre[rs].dat;
inline void insert(int &x,int l,int r,int pos,int val)
{
if(!x) x=New();
if(l==r) return tre[x].dat+=val,void();
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos,val);
else insert(rs,mid+1,r,pos,val);
push_up(x);
}
inline int merge(int x,int y)
{
if(!x||!y) return x|y; tre[x].dat+=tre[y].dat; sta.push_back(y);
ls=merge(ls,tre[y].l); rs=merge(rs,tre[y].r); return x;
}
inline int query(int x,int l,int r,int L,int R)
{
if(!x||L>R) return 0;
if(L<=l&&r<=R) return tre[x].dat;
int mid=(l+r)>>1;ll sum=0;
if(L<=mid) sum+=query(ls,l,mid,L,R);
if(R>mid) sum+=query(rs,mid+1,r,L,R);
return sum;
}
void dfs(int x)
{
insert(root[x],1,lim,s[x],1);
for(int i=head[x];i;i=nxt[i])
{
if(ver[i]==fa[x]) continue; fa[ver[i]]=x; dfs(ver[i]);
root[x]=merge(root[x],root[ver[i]]),root[ver[i]]=0;
}
int temp=query(root[x],1,lim,1,s[x]-1); ans[1]+=temp; if(x==1) return ;
ans[x]-=temp+query(root[x],1,lim,1,s[fa[x]]-1);
}
void dfs2(int x){ans[x]+=ans[fa[x]]; for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa[x]) dfs2(ver[i]);}
int main()
{
freopen("tears.in","r",stdin); freopen("tears.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++) s[i]=read(),lim=max(lim,s[i]);
for(int i=1,x,y;i<n;i++) x=read(),y=read(),add_edge(x,y),add_edge(y,x);
dfs(1); for(int i=2;i<=n;i++) ans[i]+=query(root[1],1,lim,1,s[i]-1);
dfs2(1); while(m--){int x;x=read();write(ans[x]);putchar('\n');}
return 0;
}

树状数组

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
#define ls tre[x].l
#define rs tre[x].r
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;
}
inline void write(ll x)
{
#define sta number
int sta[70],top=0; if(x<0) putchar('-'),x=~(x-1);
while(x) sta[++top]=x%10,x/=10; if(!top) sta[++top]=0;
while(top) putchar(sta[top--]+'0');
#undef sta
}
const int N=1e6+10;
int n,m,lim,cnt,s[N],fa[N],lsh[N],pre[N];
int tot=1,head[N],ver[N<<1],nxt[N<<1];
struct BIT
{
int tre[N];
inline int lowbit(int x){return x&(-x);}
void insert(int x){for(int i=x;i<=lim;i+=lowbit(i))tre[i]++;}
int query(int x){int sum=0;for(int i=x;i>0;i-=lowbit(i))sum+=tre[i];return sum;}
}T;
ll ans[N];
void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x)
{
int tmp1=T.query(s[x]-1),tmp2=T.query(s[fa[x]]-1); T.insert(s[x]);
for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa[x]) fa[ver[i]]=x,dfs(ver[i]);
int temp=T.query(s[x]-1)-tmp1; ans[1]+=temp;
if(x!=1) ans[x]-=temp+T.query(s[fa[x]]-1)-tmp2;
}
void dfs2(int x){ans[x]+=ans[fa[x]]; for(int i=head[x];i;i=nxt[i]) if(ver[i]!=fa[x]) dfs2(ver[i]);}
int main()
{
freopen("tears.in","r",stdin); freopen("tears.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++) s[i]=read(),lsh[++cnt]=s[i];
sort(lsh+1,lsh+cnt+1); lim=cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
for(int i=1;i<=n;i++) s[i]=lower_bound(lsh+1,lsh+cnt+1,s[i])-lsh,pre[s[i]]++;
for(int i=1;i<=cnt;i++) pre[i]+=pre[i-1];
for(int i=1,x,y;i<n;i++) x=read(),y=read(),add_edge(x,y),add_edge(y,x);
dfs(1); for(int i=2;i<=n;i++) ans[i]+=pre[s[i]-1];
dfs2(1); while(m--){int x;x=read();write(ans[x]);putchar('\n');}
return 0;
}

T3 传统艺能

解题思路

线段树维护矩阵乘的题目还是第一次做。。

对于一个以 A 结尾的矩阵,他的对角线都是 1 ,然后第一行也是 1 。 \(A_{i,j}\) 表示以 \(i\) 开头在结尾多一个 \(j\) 的答案,转移方程类似矩阵乘,原因显然。

线段树维护的每一个节点都是一个矩阵,每次区间查询单点修改即可。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
#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=1e5+10,mod=998244353;
int n,m;
char s[N];
struct Square
{
int a[4][4];
void clear(){memset(a,0,sizeof(a));}
Square friend operator * (Square x,Square y)
{
Square z; z.clear();
for(int i=0;i<=3;i++) for(int j=0;j<=3;j++) for(int k=0;k<=3;k++) z.a[i][j]+=x.a[i][k]*y.a[k][j];
for(int i=0;i<=3;i++) for(int j=0;j<=3;j++) z.a[i][j]%=mod; return z;
}
}S[4];
struct Segment_Tree
{
Square tre[N<<2];
#define push_up(x) tre[x]=tre[ls]*tre[rs];
void update(int x,int l,int r,int pos,int val)
{
if(l==r) return tre[x]=S[val],void();
int mid=(l+r)>>1;
if(pos<=mid) update(ls,l,mid,pos,val);
else update(rs,mid+1,r,pos,val);
push_up(x);
}
Square query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x]; int mid=(l+r)>>1;
if(L<=mid&&R>mid) return query(ls,l,mid,L,R)*query(rs,mid+1,r,L,R);
if(L<=mid) return query(ls,l,mid,L,R); return query(rs,mid+1,r,L,R);
}
}T;
#undef int
int main()
{
#define int long long
freopen("string.in","r",stdin); freopen("string.out","w",stdout);
n=read(); m=read(); scanf("%s",s+1);
for(int i=0;i<=3;i++) S[1].a[i][i]=S[2].a[i][i]=S[3].a[i][i]=1;
for(int i=0;i<=3;i++) S[1].a[1][i]=S[2].a[2][i]=S[3].a[3][i]=1;
for(int i=1;i<=n;i++) T.update(1,1,n,i,s[i]-'A'+1);
while(m--)
{
int opt,l,r,p,ans=0; char ch; opt=read();
if(opt==1){p=read();ch=getchar();T.update(1,1,n,p,ch-'A'+1);continue;}
l=read(); r=read(); Square temp=T.query(1,1,n,l,r);
for(int i=1;i<=3;i++) ans=(ans+temp.a[i][0])%mod; printf("%lld\n",ans);
}
return 0;
}

T4 铺设道路

解题思路

维护一个差分数组,最后消成 0 。

显然的时间就是 \(\sum\limits_{i=1}^n\max(0,s_i)\)

为了让答案尽可能的大,我们需要对于每个点消除距离最近的点,把较远的留给后面。

对于让答案尽可能小的情况反之。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
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=3e5+10,mod=1e9+7;
int n,tim,maxn,minn,head,tail,s[N];
pair<int,int> q[N];
void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
#undef int
int main()
{
#define int long long
freopen("road.in","r",stdin); freopen("road.out","w",stdout);
n=read(); for(int i=1,pre=0;i<=n;i++) s[i]=read()-pre,pre+=s[i],tim+=max(0ll,s[i]);
head=1; tail=0;
for(int i=1;i<=n;i++)
{
if(s[i]>0){q[++tail]=make_pair(i,s[i]);continue;}
int temp=s[i];
while(temp<0)
{
int x=q[head].first,val=q[head].second;
if(val<=-temp){head++;temp+=val;add(minn,val*(i-x)%mod*(i-x)%mod);continue;}
q[head]=make_pair(x,val+temp); add(minn,-temp*(i-x)%mod*(i-x)%mod); break;
}
}
while(head<=tail) add(minn,q[head].second*(n-q[head].first+1)%mod*(n-q[head].first+1)%mod),head++; head=1; tail=0;
for(int i=1;i<=n;i++)
{
if(s[i]>0){q[++tail]=make_pair(i,s[i]);continue;}
int temp=s[i];
while(temp<0)
{
int x=q[tail].first,val=q[tail].second;
if(val<=-temp){tail--;temp+=val;add(maxn,val*(i-x)%mod*(i-x)%mod);continue;}
q[tail]=make_pair(x,val+temp); add(maxn,-temp*(i-x)%mod*(i-x)%mod); break;
}
}
while(head<=tail) add(maxn,q[head].second*(n-q[head].first+1)%mod*(n-q[head].first+1)%mod),head++;
printf("%lld\n%lld\n%lld",tim,maxn,minn); return 0;
}

NOIP模拟83(多校16)的更多相关文章

  1. Noip模拟83 2021.10.26

    T1 树上的数 有手就能在衡中$OJ$上过,但是$WaitingCoders$不行,就是这样 必须使用$O(n)$算法加上大力卡常,思路就是找子树内没更新的更新,更新过了直接$return$ 1 #i ...

  2. Noip模拟54 2021.9.16

    T1 选择 现在发现好多题目都是隐含的状压,不明面给到数据范围里,之凭借一句话 比如这道题就是按照题目里边给的儿子数量不超过$10$做状压,非常邪门 由于数据范围比较小,怎么暴力就怎么来 从叶子节点向 ...

  3. Noip模拟41 2021.8.16

    T1 你相信引力吗 对于区间的大小关系问题,往往使用单调栈来解决 这道题的优弧和劣弧很烦,考虑将其等价的转化 由于所有的合法情况绕过的弧都不会经过最高的冰锥, 又因为环可以任意亲定起点,这样可以直接把 ...

  4. Noip模拟17 2021.7.16

    我愿称这场考试为STL专练 T1 世界线 巧妙使用$bitset$当作vis数组使用,内存不会炸,操作还方便,的确是极好的. 但是这个题如果不开一半的$bitset$是会炸内存的,因为他能开得很大,但 ...

  5. Noip模拟78 2021.10.16

    这次时间分配还是非常合理的,但可惜的是$T4$没开$\textit{long long}$挂了$20$ 但是$Arbiter$上赏了蒟蒻$20$分,就非常不错~~~ T1 F 直接拿暴力水就可以过,数 ...

  6. NOIP模拟92(多校25)

    前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...

  7. NOIP模拟84(多校17)

    T1 宝藏 解题思路 考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了?? 考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的 ...

  8. NOIP模拟85(多校18)

    前言 好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨). 然后我只知道 T1 的莓,确实挺惨... T1 莓良心 解题思路 首先答案只与 \(w\) 的和有关系,于是问题就 ...

  9. NOIP模拟86(多校19)

    T1 特殊字符串 解题思路 \(f_{i,j}\) 表示前 \(i\) 个字符中结尾为 \(j\) 的最大贡献. 转移枚举当前位置于之前位置结尾的组合加上贡献即可. 对于边界问题,容易发现选择 1 一 ...

随机推荐

  1. Python3正则表达式学习笔记

    学习前准备:导入re模块 import re 一.re的核心函数 1 - re.compile(pattern[, flags]) 编译正则表达式,速度快 2 - re.match(pattern, ...

  2. rtl8188eu 驱动移植

    测试平台 宿主机平台:Ubuntu 16.04.6 目标机:iMX6ULL 目标机内核:Linux 4.1.15 rtl8188eu 驱动移植 在网上下载Linux版的驱动源码: wifi驱动的实现有 ...

  3. Pytest系列(15)- 多重校验插件之pytest-assume的详细使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 pytest中可以用pyth ...

  4. 如何让阿三 Windows 10、11 的恢复分区(Recovery Partition)恢复到 “盖茨” 模式

    如何将 Windows Server 2022 的恢复分区(Recovery Partition)移动到 C 盘之前,恢复 C 盘容量调整功能. 请访问原文链接:https://sysin.org/b ...

  5. java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.xxx.Json.NewsBean.getError_code()' on a null object reference错误解决

    AS在运行的过程中出现了错误: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.xx ...

  6. Python程序调用摄像头实现人脸识别

    使用简单代码实现摄像头进行在线人脸识别 import cv2 import sys import logging as log import datetime as dt from time impo ...

  7. MapReduce原理深入理解(一)

    1.MapReduce概念 1)MapReduce是一种分布式计算模型,由Google提出,主要用于搜索领域,解决海量数据的计算问题. 2)MapReduce是分布式运行的,由两个阶段组成:Map和R ...

  8. [转载20131024]Nginx服务器漏洞的利用和修复方法

    本文主要分为两大部分,第一部分介绍了Nginx的一些常见安全漏洞的形成原因.利用方法,并给出了相应的解决办法;第二部分介绍了Nginx安全加固时需要关注的主要内容. Nginx(发音同engine x ...

  9. 这两个基础seo插件,wordpress网站必装

    WordPress对搜索引擎非常友好,这一点很多人都知道.不过我们在制作完成WordPress主题后,还可以在原来的良好基础上,添加两个队seo非常有利的WordPress插件. 第一个插件:Baid ...

  10. 数值分析:幂迭代和PageRank算法

    1. 幂迭代算法(简称幂法) (1) 占优特征值和占优特征向量 已知方阵\(\bm{A} \in \R^{n \times n}\), \(\bm{A}\)的占优特征值是量级比\(\bm{A}\)所有 ...