2021.10.26考试总结[冲刺NOIP模拟16]
T1 树上的数
\(DFS\)一遍。结构体存边好像更快?
\(code:\)
T1
#include<bits/stdc++.h>
using namespace std;
namespace IO{
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;
const int NN=5000010;
int n,m,a,b,f,q,x,y,sum,ans;
int idx,head[NN];
bool vis[NN];
struct edge{ int to,nex; }e[NN];
void dfs(int s){
if(vis[s]) return;
--sum; vis[s]=1;
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to) dfs(v);
}
signed main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
sum=n=read(); m=read(); a=read(); b=read(); f=1;
for(int i=2;i<=n;++i){
e[++idx]=(edge){i,head[f]}; head[f]=idx;
f=((1ll*f*a+b)^19760817)%i+1;
}
q=read(); x=read(); y=read();
for(int i=1;i<=m;++i){
dfs(q); ans^=sum;
q=(((1ll*q*x+y)^19760817)^(i+1<<1))%(n-1)+2;
}
write(ans,'\n');
return 0;
}
T2 时代的眼泪
好像挺明显的换根\(DP\)。但我因为多组询问成功跑偏
考虑转换贡献,一个点的贡献即为它字数内权值小于它的点数,所有点的贡献之和即为答案。
首先不难求得\(1\)为根时的答案,接下来当根由\(x\)换成\(x\)的儿子\(y\)时,\(y\)的子树变为整棵树,\(x\)的子树变为以\(x\)为根时树中\(y\)子树外的部分。
可以树上主席树维护信息,但范围\(1e6\),主席树优秀的常数使它无法通过本题。可以用树状数组在\(DFS\)中记录遍历完子树后权值在某个范围的变化量来代替。
\(code:\)
T2
#include<bits/stdc++.h>
using namespace std;
namespace IO{
auto read=[]()->int{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
};
void write(long long x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;
const int NN=1000010;
int n,q,u,w[NN],wn[NN],wf[NN];
long long f[NN];
int idx,head[NN];
struct edge{ int to,nex; }e[NN<<1];
int ext,has[NN];
auto add=[](int a,int b)->void{
e[++idx]=(edge){b,head[a]}; head[a]=idx;
e[++idx]=(edge){a,head[b]}; head[b]=idx;
};
namespace BIT{
int c[NN];
auto insert=[](int pos,int x)->void{ while(pos<=n+1){ c[pos]+=x; pos+=pos&-pos; } };
auto query=[](int pos)->int{ int res=0; while(pos){ res+=c[pos]; pos-=pos&-pos; } return res; };
void DFS(int s,int fa){
f[1]+=query(n+1)-query(w[s]);
insert(w[s],1);
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to)
if(v!=fa) DFS(v,s);
insert(w[s],-1);
}
void Dfs(int s,int fa){
wn[s]=-query(w[s]-1);
if(fa) wf[s]=-query(w[fa]-1);
insert(w[s],1);
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to)
if(v!=fa) Dfs(v,s);
wn[s]+=query(w[s]-1);
if(fa) wf[s]+=query(w[fa]-1);
}
} using namespace BIT;
void dfs(int s,int fa){
for(int i=head[s],v=e[i].to;i;i=e[i].nex,v=e[i].to) if(v!=fa){
f[v]=f[s]-wn[v]+query(w[v]-1)-wf[v];
dfs(v,s);
}
}
signed main(){
freopen("tears.in","r",stdin);
freopen("tears.out","w",stdout);
n=read(); q=read();
for(int i=1;i<=n;i++)
w[i]=read(),has[i]=w[i];
sort(has+1,has+n+1); ext=unique(has+1,has+n+1)-has-1;
for(int i=1;i<=n;i++)
w[i]=lower_bound(has+1,has+ext+1,w[i])-has+1;
for(int a,b,i=1;i<n;i++)
a=read(),b=read(),add(a,b);
DFS(1,0); Dfs(1,0); dfs(1,0);
while(q--){
u=read();
printf("%lld\n",f[u]);
}
return 0;
}
T3 传统艺能
对这类问题有很经典的\(DP\)。设\(f_c\)表示以\(c\)结尾的本质不同子序列个数,有
\]
这个转移是线性的,加上本题字符集只有\(3\),可以考虑矩阵优化。可以预处理出每个字符对应的转移矩阵,用线段树维护矩阵即可。
\(code:\)
T3
#include<bits/stdc++.h>
using namespace std;
namespace IO{
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;
const int NN=100010,mod=998244353;
int n,m,x,y,op,num[NN];
char t,ch[NN];
void add(int& a,int b){ a=(a+b>=mod)?(a+b-mod):(a+b); }
namespace segment_tree{
#define ld rt<<1
#define rd (rt<<1)|1
struct mat{
int s[4][4];
mat(){}
mat(int x){ memset(s,0,sizeof(s)); s[0][0]=s[1][1]=s[2][2]=s[3][3]=x; }
void print(){for(int i=0;i<=3;i++)for(int j=0;j<=3;j++)write(s[i][j],j==3?'\n':' ');puts("");}
mat operator*(const mat& a)const{
mat res=mat(0);
for(int i=0;i<=3;i++)
for(int k=0;k<=3;k++)
for(int j=0;j<=3;j++)
add(res.s[i][j],1ll*s[i][k]*a.s[k][j]%mod);
return res;
}
}st,ans,tmp,base[4],mt[NN<<2];
void init(){
st.s[0][0]=1;
base[1]=mat(1); base[2]=mat(1); base[3]=mat(1);
base[1].s[0][1]=base[1].s[1][1]=base[1].s[2][1]=base[1].s[3][1]=1;
base[2].s[0][2]=base[2].s[1][2]=base[2].s[2][2]=base[2].s[3][2]=1;
base[3].s[0][3]=base[3].s[1][3]=base[3].s[2][3]=base[3].s[3][3]=1;
}
void pushup(int rt){ mt[rt]=mt[ld]*mt[rd]; }
void build(int rt,int l,int r){
if(l==r) return mt[rt]=base[num[l]],void();
int mid=l+r>>1;
build(ld,l,mid);
build(rd,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int pos,int typ){
if(l==r) return mt[rt]=base[typ],void();
int mid=l+r>>1;
if(pos<=mid) update(ld,l,mid,pos,typ);
else update(rd,mid+1,r,pos,typ);
pushup(rt);
}
mat query(int rt,int l,int r,int opl,int opr){
if(l>=opl&&r<=opr) return mt[rt];
int mid=l+r>>1;
mat res=mat(1);
if(opl<=mid) res=res*query(ld,l,mid,opl,opr);
if(opr>mid) res=res*query(rd,mid+1,r,opl,opr);
return res;
}
} using namespace segment_tree;
signed main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
n=read(); m=read();
scanf("%s",ch+1);
for(int i=1;i<=n;i++)
num[i]=ch[i]-'A'+1;
init(); build(1,1,n);
while(m--){
op=read();
if(op==1){
x=read(); cin>>t;
update(1,1,n,x,t-'A'+1);
} else{
x=read(); y=read();
ans=st*query(1,1,n,x,y);
add(ans.s[0][1],ans.s[0][2]); add(ans.s[0][1],ans.s[0][3]);
printf("%d\n",ans.s[0][1]);
}
}
return 0;
}
T4 铺设道路
考虑通过差分将区间问题转化为单点问题。令\(b_i=d_{i-1}-d_i\),那么每次操作就是选取\(l,r\),使\(b_l-1,b_r+1\),代价为\((r-l)^2\),最终要将所有\(b\)置为\(0\)。(包括\(b_{n+1}\))
要使时间最短,就要保证每次操作都是有效的,即\(b_l>0,b_r<0\)。
可以维护一个队列,扫一遍\(b\),遇到\(b>0\)则插入队列,\(b<0\)则找队中元素将其消去。因为\(d\geq 0\),所以一定能消完。
要求最大值则优先消队尾元素,反之优先消队尾元素。
\(code:\)
T4
#include<bits/stdc++.h>
using namespace std;
namespace IO{
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;
const int NN=100010,mod=998244353;
int n,m,x,y,op,num[NN];
char t,ch[NN];
void add(int& a,int b){ a=(a+b>=mod)?(a+b-mod):(a+b); }
namespace segment_tree{
#define ld rt<<1
#define rd (rt<<1)|1
struct mat{
int s[4][4];
mat(){}
mat(int x){ memset(s,0,sizeof(s)); s[0][0]=s[1][1]=s[2][2]=s[3][3]=x; }
void print(){for(int i=0;i<=3;i++)for(int j=0;j<=3;j++)write(s[i][j],j==3?'\n':' ');puts("");}
mat operator*(const mat& a)const{
mat res=mat(0);
for(int i=0;i<=3;i++)
for(int k=0;k<=3;k++)
for(int j=0;j<=3;j++)
add(res.s[i][j],1ll*s[i][k]*a.s[k][j]%mod);
return res;
}
}st,ans,tmp,base[4],mt[NN<<2];
void init(){
st.s[0][0]=1;
base[1]=mat(1); base[2]=mat(1); base[3]=mat(1);
base[1].s[0][1]=base[1].s[1][1]=base[1].s[2][1]=base[1].s[3][1]=1;
base[2].s[0][2]=base[2].s[1][2]=base[2].s[2][2]=base[2].s[3][2]=1;
base[3].s[0][3]=base[3].s[1][3]=base[3].s[2][3]=base[3].s[3][3]=1;
}
void pushup(int rt){ mt[rt]=mt[ld]*mt[rd]; }
void build(int rt,int l,int r){
if(l==r) return mt[rt]=base[num[l]],void();
int mid=l+r>>1;
build(ld,l,mid);
build(rd,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int pos,int typ){
if(l==r) return mt[rt]=base[typ],void();
int mid=l+r>>1;
if(pos<=mid) update(ld,l,mid,pos,typ);
else update(rd,mid+1,r,pos,typ);
pushup(rt);
}
mat query(int rt,int l,int r,int opl,int opr){
if(l>=opl&&r<=opr) return mt[rt];
int mid=l+r>>1;
mat res=mat(1);
if(opl<=mid) res=res*query(ld,l,mid,opl,opr);
if(opr>mid) res=res*query(rd,mid+1,r,opl,opr);
return res;
}
} using namespace segment_tree;
signed main(){
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
n=read(); m=read();
scanf("%s",ch+1);
for(int i=1;i<=n;i++)
num[i]=ch[i]-'A'+1;
init(); build(1,1,n);
while(m--){
op=read();
if(op==1){
x=read(); cin>>t;
update(1,1,n,x,t-'A'+1);
} else{
x=read(); y=read();
ans=st*query(1,1,n,x,y);
add(ans.s[0][1],ans.s[0][2]); add(ans.s[0][1],ans.s[0][3]);
printf("%d\n",ans.s[0][1]);
}
}
return 0;
}
2021.10.26考试总结[冲刺NOIP模拟16]的更多相关文章
- 2021.10.27考试总结[冲刺NOIP模拟17]
T1 宝藏 发现每个数成为中位数的长度是关于权值单调的.线段树二分判断是否合法,单调指针扫即可. 考场上写了二分,平添\(\log\). \(code:\) T1 #include<bits/s ...
- 2021.7.15考试总结[NOIP模拟16]
ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...
- 2016 10 26考试 NOIP模拟赛 杂题
Time 7:50 AM -> 11:15 AM 感觉今天考完后,我的内心是崩溃的 试题 考试包 T1: 首先看起来是个贪心,然而,然而,看到那个100%数据为n <= 2000整个人就虚 ...
- Noip模拟83 2021.10.26
T1 树上的数 有手就能在衡中$OJ$上过,但是$WaitingCoders$不行,就是这样 必须使用$O(n)$算法加上大力卡常,思路就是找子树内没更新的更新,更新过了直接$return$ 1 #i ...
- 2021.10.15考试总结[NOIP模拟77]
\(n=40\)考虑\(meet \;in \;the \;middle\) 某个元素有关的量只有一个时考虑转化为树上问题 对暴力有自信,相信数据有梯度 没了 UPD:写了个略说人话的. T1 最大或 ...
- 2021.10.18考试总结[NOIP模拟76]
T1 洛希极限 不难发现每个点肯定是被它上一行或上一列的点转移.可以预处理出每个点上一行,上一列最远的能转移到它的点,然后单调队列优化. 预处理稍显ex.可以用并查集维护一个链表,记录当前点之后第一个 ...
- 2021.10.12考试总结[NOIP模拟75]
T1 如何优雅的送分 考虑式子的实际意义.\(2^{f_n}\)实际上就是枚举\(n\)质因子的子集.令\(k\)为这个子集中数的乘积,就可以将式子转化为枚举\(k\),计算\(k\)的贡献. 不难得 ...
- 2021.10.11考试总结[NOIP模拟74]
T1 自然数 发现\(mex\)是单调不降的,很自然地想到用线段树维护区间端点的贡献. 枚举左端点,用线段树维护每个右端点形成区间的\(mex\)值.每次左端点右移相当于删去一个数. 记\(a_i\) ...
- 2021.10.9考试总结[NOIP模拟72]
T1出了个大阴间题 状压\(DP\),记当前状态的代价和与方案数.状态\(\Theta(2^nn)\),转移\(\Theta(n)\). 发现每个状态的最大值只会是所选集合的\(max\)或加一.于是 ...
随机推荐
- Configuration对象和SessionFactory会话池
一.加载核心配置文件方式 二.加载映射文件方式 三.SessionFactory相当于连接池 四.获取session会话 同一个线程中获取的session两种方法获取的是同一个session对象: 不 ...
- 远程线程注入DLL突破session 0 隔离
远程线程注入DLL突破session 0 隔离 0x00 前言 补充上篇的远程线程注入,突破系统SESSION 0 隔离,向系统服务进程中注入DLL. 0x01 介绍 通过CreateRemoteTh ...
- 【第十四篇】- Maven 自动化构建之Spring Cloud直播商城 b2b2c电子商务技术总结
Maven 自动化构建 自动化构建定义了这样一种场景: 在一个项目成功构建完成后,其相关的依赖工程即开始构建,这样可以保证其依赖项目的稳定. 比如一个团队正在开发一个项目 bus-core-api, ...
- 基于python2.7 Tkinter 做一个小工具
1.源码:先写一个界面出来,放需要放入的点击事件的函数 # -*- coding:utf-8 -*- import Tkinter from Tkinter import * import Excle ...
- 【转载】flag标志什么?哦,它标志代码馊了
几乎每次在代码中发现flag变量,我总是能嗅到一股馊味.不管你闻没闻到,反正我闻到了. 在代码中,flag通常作为标志变量的名字.但问题在于,不是所有的问题或代码都需要使用这种标志变量,更不是使用标志 ...
- 怎么通俗的理解Netty呢?
目录 Netty(3.X) 简单体验 Netty的事件驱动机制 Netty的源码阅读 Netty(3.X) 有了Netty,你可以实现自己的HTTP服务器,FTP服务器,UDP服务器,RPC服务器,W ...
- 《手把手教你》系列技巧篇(二十七)-java+ selenium自动化测试- quit和close的区别(详解教程)
1.简介 尽管有的小伙伴或者童鞋们觉得很简单,不就是关闭退出浏览器,但是宏哥还是把两个方法的区别说一下,不然遇到坑后根本不会想到是这里的问题. 2.源码 本文介绍webdriver中关于浏览器退出操作 ...
- 鸿蒙内核源码分析(中断切换篇) | 系统因中断活力四射 | 百篇博客分析OpenHarmony源码 | v42.02
百篇博客系列篇.本篇为: v42.xx 鸿蒙内核源码分析(中断切换篇) | 系统因中断活力四射 | 51.c.h .o 硬件架构相关篇为: v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪 ...
- MySQL高可用架构-MMM、MHA、MGR、PXC
主从复制如何工作 在主库把数据记录到binlog(二进制日志). 备库开IO线程把binlog复制到自己的relaylog(中继日志). 备库读取中继日志,重放到备库上. 半同步复制 半同步复制可以确 ...
- 【数据结构与算法】二叉树的 Morris 遍历(前序、中序、后序)
前置说明 不了解二叉树非递归遍历的可以看我之前的文章[数据结构与算法]二叉树模板及例题 Morris 遍历 概述 Morris 遍历是一种遍历二叉树的方式,并且时间复杂度O(N),额外空间复杂度O(1 ...