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\)或加一.于是 ...
随机推荐
- 1004. 最大连续1的个数 III
1004. 最大连续1的个数 III 给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 . 返回仅包含 1 的最长(连续)子数组的长度. 示例 1: 输入:A = ...
- EcShop调用显示指定分类下的子分类方法
ECSHOP首页默认的只有全部分类,还有循环大类以及下面小类的代码,貌似没有可以调用显示指定大类下的子分类代码.于是就有这个文章的产生了,下面由夏日博客来总结下网站建设过程中ECSHOP此类问题的网络 ...
- Matlab使用随记
Matlab 2020 想要看图像每一点的值大小 工具--->数据提示 想要导出的分辨率提高 导出设置--->渲染--->600dpi Matlab 2017b 程序运行后,画出图, ...
- jQuery has been removed
jQuery has been removed, 新的项目不要用jQuery了 这些问题都已经有了解决方案 * $()选择器, * $.ajax, * $dom.on("click" ...
- jquery 设置django全局token
通过JQUEYR中的ajaxSetup,来设置django中的token,即不需要再每次都去引用: 第一步: 先django中的html中设置 {% csrf_token %} 第二步: 新一个js ...
- 总结了下PHPExcel官方读取的几个例子
1.使用 PHPExcel_IOFactory 读取文件 $objPHPExcel = PHPExcel_IOFactory::load($inputFileName); 2.使用一个特定的读取类,读 ...
- 安卓模拟器genymotion安装
上一篇已经讲了appium的搭建.那么搭建好后,我们需要测试不同机型,这个时候除了真机外,可以选择安装模拟器.市面上的模拟器有很多:夜神.逍遥.mumu.android emulator.genymo ...
- Kafka与RocketMq文件存储机制对比
一个商业化消息队列的性能好坏,其文件存储机制设计是衡量一个消息队列服务技术水平和最关键指标之一. 开头问题 kafka文件结构和rocketMQ文件结构是什么样子?特点是什么? 一.目录结构 Kafk ...
- 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 百篇博客分析OpenHarmony源码 | v69.01
百篇博客系列篇.本篇为: v69.xx 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说 ...
- Docker入门系列之五:15个 Docker 命令
在这篇文章中,我们将学习15个Dockers CLI命令.如果你还不了解Docker,请查看这个系列的其他部分进行学习,Docker概念,生态系统,Dockerfile,Docker镜像. Docke ...