前言

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. python 修改图像大小和分辨率

    1 概念: 分辨率,指的是图像或者显示屏在长和宽上各拥有的像素个数.比如一张照片分辨率为1920x1080,意思是这张照片是由横向1920个像素点和纵向1080个像素点构成,一共包含了1920x108 ...

  2. DPDK 无锁环形队列(Ring)详解

    DPDK 无锁环形队列(Ring) 此篇文章主要用来学习和记录DPDK中无锁环形队列相关内容,结合了官方文档说明和源码中的实现,供大家交流和学习. Author : Toney Email : vip ...

  3. C语言中volatile、register、const、static、extern、 auto关键字的作用

    一.volatile详解 volatile的本意是"易变的" 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据.当要求使用volat ...

  4. web服务器之Ser-U和NFS

    1. Ser-U加载页面目录/文件列表 2. Ser-U下载文件 3. NFS服务器加载目录/文件列表 4. NFS服务器下载文件 4. 对比分析 Ser-U服务器在传输服务器端的目录时,使用的为xm ...

  5. Mybatis-基本学习(上)

    目录 Mybatis mybatis开始 -----环境准备 一.简介 1.什么是MyBatis 2.持久化 3.持久层 4.为什么需要Mybatis? 二.第一个Mybatis程序 1.搭建环境 1 ...

  6. LVS+keepalived集群

    一.Keepalived工具介绍专为LVS和HA设计的一款健康检查工具 支持故障自动切换(Failover) 支持节点健康状态检查(Health Checking) 官方网站:http://www.k ...

  7. Apache配置与应用

    目录: 一.基于域名的虚拟主机 二.基于IP地址的虚拟主机 三.基于端口的虚拟主机 四.Apache连接保持 五.构建Web虚拟目录与用户授权限制 六.Apache日志分割 七.AWStats 分析系 ...

  8. c++ if语句讲解&例题

    一.if语句 1.基本语法: if(条件 布尔型){ 当条件符合执行的语句 } 2.例子: #include <iostream> using namespace std; int mai ...

  9. 入坑微信小程序必经之路(六)图片上传服务器——WebSercice接口

    wxml文件 <view class="weui-uploader"> <view class="img-v weui-uploader__bd&quo ...

  10. Shell系列(19)- 正则表达式

    正则表达式与通配符 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配.grep,awk,sed等命令可以支持正则表达式. 通配符用来匹配符号条件的文件名,通配符是完全匹配.ls,find,c ...