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\)或加一.于是 ...
随机推荐
- 关于Golang的学习路线
基础 安装golang环境 Golang基础,流程控制,函数,方法,面向对象 网络编程(自己做一个简单的tcp的聊天室,websocket,http,命令行工具) 并发(可以看一下并发爬虫或者下载器的 ...
- 微信小程序开发正常,真机预览模式错误
原因是开发时设置了不检查域名是否合法,去后台设置上就可以了
- c# List集合类常用操作:二、增加
所有操作基于以下类 class Employees { public int Id { get; set; } public string Name { get; set; } public stri ...
- 使用easyui进行上左右布局
在后台管理系统开发的过程中,上左右的布局是最常见的页面布局方式,现在我们来看看使用easyui这个jquery前端框架如何快速搭建一个可用的页面框架. 1.在页面中引入easyui所需的文件 1 &l ...
- 如何在win10中Java中JDK的安装和path,classpath的环境配置
1,第一步,不用说肯定是去下一个java JDK了.目前最新版本的java JDK应该是JDK 7.0,这个就自己去百度一下了,好多网站都可以找到.2,第二步就是安装JDK虚拟机了,按照它里面的提示一 ...
- ECShop 文章添加缩略图功能
为 ECShop 文章添加缩略图 ECShop 文章不包含缩略图比较遗憾,不过它的文章里包含一个附件上传,而且一般不会用到,这样,我们就可以改动一下,让它成为缩略图. 首先在 includes ...
- Docker系列(4)- run的流程和docker原理
回顾HelloWorld流程 底层工作原理 Docker是怎么工作的? Docker是一个Client-Server结构的系统,Docker的守护进程运行在宿主机上.通过Socket从客户端访问 Do ...
- uni-app跨平台框架介绍和快速入门
前言: 首先今天主要介绍的是一个多平台的前端框架uni-app,关于多平台的前端框架网上有很多成熟的解决方案比如说Taro,React Native,Flutter等这些都是一些非常优秀的前端跨平台的 ...
- Appium和Selenium的区别和联系
https://www.cnblogs.com/lv-lxz/p/11118862.html https://blog.csdn.net/weixin_42139375/article/details ...
- 今天我抓了个 HTTPS 的包
之前写过一篇讲 HTTPS 的思想的文章. 破玩意 | 用 HTTPS 传纸条 后来又写了篇用更凝练的语言总体描述了 HTTPS 的主干. 叮咚 | HTTPS 的分支和主干 想必通过这两篇文章,HT ...