考试过程:

刚看完题,发现T1是个类lis 问题,但要求$O(nlogn)$,应该是个数据结构优化dp,T2应该是个数据结构,T3是个字符串?没有匹配,不会是后缀数组吧,这是NOIP模拟啊,可能是个dp。

开始分析T1,一开始想错了,以为只要一个树状数组就可以,是个全场切的sb题,后来发现过不了样例,后来发现是假的,然后默默的开始打$O(n^3)$暴力dp,半个小时后过了两个样例,60应该是稳了,怕后面题时间不够,就先看了后两题,第二题除了$O(n^2)$暴力啥也不会,T3觉得dp好像很可做,然后开始推,但一直想不到怎么去重,浪费了好多时间,最后T2打了暴力,T3根本没动。

觉得100+还是挺稳的,点开成绩,woc T1 CE!!! T2 WA0 艹,为什么啊。

我为什么要手贱手打max阿,还不编译。T2测试点分治 没return 0; 我@%$^*#&%^@#......

感觉考试的时候不太认真,不然也不会犯这么sb的错误,本来拿分就拿不过别人,还犯这种低级错误,感觉那天白跟教练谈了,真tm是不长记性。

题解:

T1 队长快跑

线段树优化dp,考场上打的是$O(n^3)$ 的,然后觉得优化空间不大,就没有往细里想,其实暴力完全可以做到$O(n^2)$。

然后线段树优化就比较显然了然而我蒟蒻就是想不到啊。

设$dp_{i,j}$表示处理完$i$个水晶并且当$a[i]$最小值为$j$的最优解

那么我们进行分类讨论

如果$a[i]<b[i]$ 那么$dp_{i,a[i]}=\max{dp_{i,j}}+1,j>=b[i]+1,j<=MAX$

否则$dp_{i,a[i]}=\max{dp_{i,a[i]}},j>=a[i]+1,j<=MAX $

  $dp_{i,j}=dp_{i,j-1}+1,j>b[i],j<=a[i]$

那么我们只要把第二维放到线段树上维护一下就好了

这样就只需要一颗支持区间修改,单点修改,区间查询就好了。

 #include<bits/stdc++.h>
#define lowbit(x) x&(-x)
using namespace std;
const int N=1e5+;
int a[N],b[N];
int c[N<<];
int n;
int t=,len,q_mx;
struct SegmentTree{
int l,r,mx,lazy;
}tr[N<<];
int max(int a,int b){
return a>b?a:b;
}
void down(int p){
if(!tr[p].lazy) return ;
tr[p<<].lazy+=tr[p].lazy;
tr[p<<|].lazy+=tr[p].lazy;
tr[p<<].mx+=tr[p].lazy;
tr[p<<|].mx+=tr[p].lazy;
tr[p].lazy=;
} void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
if(l==r){
tr[p].mx=;
return ;
}
int mid=(l+r)>>;
build(p<<,l,mid);
build(p<<|,mid+,r);
tr[p].mx=max(tr[p<<].mx,tr[p<<|].mx);
}
void update(int p,int ll,int rr,int l,int r,int val){
if(ll<=l&&r<=rr){
tr[p].lazy+=val;
tr[p].mx+=val;
return ;
}
down(p);
int mid=(tr[p].l+tr[p].r)>>;
if(ll<=mid) update(p<<,ll,rr,l,mid,val);
if(rr>mid) update(p<<|,ll,rr,mid+,r,val);
tr[p].mx=max(tr[p<<].mx,tr[p<<|].mx);
}
void modify(int p,int l,int r,int pos,int val){
if(l==r){//cout<<val<<endl;
tr[p].mx=max(tr[p].mx,val);
// cout<<tr[p].mx<<endl;
return ;
}
down(p);
int mid=(tr[p].l+tr[p].r)>>;
if(pos<=mid) modify(p<<,l,mid,pos,val);
else modify(p<<|,mid+,r,pos,val);
tr[p].mx=max(tr[p<<].mx,tr[p<<|].mx);
}
void query(int p,int ll,int rr,int l,int r){
if(ll<=l&&r<=rr){//cout<<"tr=="<<tr[p].mx<<" mx=="<<q_mx<<endl;
q_mx=max(tr[p].mx,q_mx);
return ;
}
down(p);
int mid=(tr[p].l+tr[p].r)>>;
if(ll<=mid) query(p<<,ll,rr,l,mid);
if(rr>mid) query(p<<|,ll,rr,mid+,r);
}
int main(){
// freopen("leader.in","r",stdin);
// freopen("leader.out","w",stdout);
scanf("%d",&n);
int Max=;
for(int i=;i<=n;++i){
scanf("%d%d",&a[i],&b[i]);
c[++t]=a[i];
c[++t]=b[i];
Max=max(Max,a[i]);
}
sort(c+,c+t+);
len=unique(c+,c+t+)-c-;
for(int i=;i<=n;++i) {
a[i]=lower_bound(c+,c+len+,a[i])-c;
b[i]=lower_bound(c+,c+len+,b[i])-c;
}
// for(int i=1;i<=n;++i) cout<<a[i]<<" ";
// cout<<endl;
// for(int i=1;i<=n;++i) cout<<b[i]<<" ";
// for(int i=1;i<=n;++i) cout<<a[i]<<" "<<b[i]<<endl;
build(,,len);
for(int i=;i<=n;++i){
q_mx=;
if(a[i]<=b[i]){
query(,b[i]+,len,,len);
modify(,,len,a[i],q_mx+);
}
else{
query(,a[i]+,len,,len);
update(,b[i]+,a[i],,len,);
modify(,,len,a[i],q_mx+);
}
// cout<<"q_mx=="<<q_mx<<endl;
}
printf("%d",tr[].mx);
}

leader

T2 影魔

大神数据结构题

不难想到的是对于每一个节点开线段树但我就是想不到。

但是要维护什么,就看它要干什么,我们考虑把颜色和深度联系到一起,考虑维护在每颗子树内,每种颜色出现的最小深度,但是这样我们处理不了询问,所以我们再维护在每个子树内以每个深度为最小深度的颜色种数,这样我们把第二棵线段树可持久化就能做到询问深度为的以内的询问了。

但是这样空间会爆,所以两棵线段树都要动态开点。

显然这两个信息都满足可加性,只要在dfs的过程中向上合并就好了。

还有要注意的一点就是在合并第一棵线段树是会影响到第二棵线段树的信息,即在合并第一棵线段树时把深度较大的信息在相应颜色的第二棵线段树里把贡献减掉,细节还是蛮多的,蒟蒻博主打了一个下午,主要还是对动态开点线段树,可持久化线段树理解的不透彻。

复杂度$O(nlogn)$,但常数超级大,在线的。

强烈谴责两个log过的

 #include<bits/stdc++.h>
using namespace std;
const int N=1e5+;
int tot;
int vis[N],d[N],c[N];
int fa[N];
int first[N],to[N<<],nex[N<<],cnt;
int root1[N*],root2[N*];
struct Seg1{
int l,r,val;
}tr[N*];
int n;
void build(int &x,int l,int r,int pos,int val){//root, l,r fanwei ,pos weizhi ,val quanzhi
x=++tot;
if(l==r){
tr[x].val=val;
return ;
}
int mid=(l+r)>>;
if(pos<=mid) build(tr[x].l,l,mid,pos,val);
else build(tr[x].r,mid+,r,pos,val);
} void update(int &x,int l,int r,int pos,int val){
++tot;
tr[tot]=tr[x];
x=tot;
tr[x].val+=val;
if(l==r) return ;
int mid=(l+r)>>;
if(pos<=mid) update(tr[x].l,l,mid,pos,val);
else update(tr[x].r,mid+,r,pos,val);
} int merge1(int x,int y,int l,int r,int p){//col xiabiao val shendu
if(!x||!y) return x+y;//chuan p yuanyinshi yaodui tr2 xiugai yi p weigen
int rt=++tot;
if(l==r){
tr[rt].val=min(tr[x].val,tr[y].val);
update(root2[p],,n,max(tr[x].val,tr[y].val),-);
return rt;
}
int mid=(l+r)>>;
tr[rt].l=merge1(tr[x].l,tr[y].l,l,mid,p);
tr[rt].r=merge1(tr[x].r,tr[y].r,mid+,r,p);
return rt;
}
int merge2(int x,int y,int l,int r){//dep xiabiao val col
if(!x||!y) return x+y;
int rt=++tot;
/*if(l==r){
tr[rt].val=tr[x].val+tr[y].val;
return rt;
}*/
tr[rt].val=tr[x].val+tr[y].val;
int mid=(l+r)>>;
tr[rt].l=merge2(tr[x].l,tr[y].l,l,mid);
tr[rt].r=merge2(tr[x].r,tr[y].r,mid+,r);
return rt;
}
int query(int p,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr) return tr[p].val;
int ans=,mid=(l+r)>>;
if(ll<=mid) ans+=query(tr[p].l,l,mid,ll,rr);
if(rr>mid) ans+=query(tr[p].r,mid+,r,ll,rr);
return ans;
} void add(int a,int b){
to[++cnt]=b,nex[cnt]=first[a],first[a]=cnt;
}
void pre_dfs(int x,int fa){//cout<<x<<endl;
build(root1[x],,n,c[x],d[x]);
update(root2[x],,n,d[x],);
for(int i=first[x];i;i=nex[i]){
int y=to[i];
if(y==fa) continue;
d[y]=d[x]+;
pre_dfs(y,x);
root1[x]=merge1(root1[x],root1[y],,n,x);
root2[x]=merge2(root2[x],root2[y],,n);
}
} int main(){
int m;
scanf("%d%d",&n,&m);
int Max=;
for(int i=;i<=n;++i) {scanf("%d",&c[i]);Max=max(Max,c[i]);}
for(int i=;i<n;++i){
scanf("%d",&fa[i]);
add(fa[i],i+);
}
d[]=;
pre_dfs(,);
// cout<<endl;
// cout<<tot<<endl;
// for(int i=1;i<=n;++i) cout<<root1[i]<<" ";
// cout<<endl;
// for(int i=1;i<=n;++i) cout<<root2[i]<<" ";
for(int i=;i<=m;++i){
int x,dis;
scanf("%d%d",&x,&dis);
int ans=query(root2[x],,n,d[x],d[x]+dis);
printf("%d\n",ans);
}
}

shadow

T3 抛硬币

其实还是不太难的dp,不难想到设$dp[i][j]$表示处理完位置i且长度为j的方案数

很显然的转移:

$dp[i][j]=dp[i-1][j]+dp[i-1][j-1]$,但是有好多重的,所以想怎么去重

显然一个字符只会和他一样的字符产生重复,所以我们预处理每个字符和他相同的前驱,设其为$p[i]$,那么在减掉发$dp[p[i]-1][j-1]$就好了。

需要稍预处理,细节见代码。

 #include<bits/stdc++.h>
#define cout cerr
#define int long long
using namespace std;
const int N=;
const int mod=;
int f[N][N];
char s[N];
int p[N];
int sum[N],vis[N];
signed main(){
int l;
scanf("%s",s+);
scanf("%lld",&l);
int n=strlen(s+);
for(int i=;i<=n;++i){
sum[i]=sum[i-];
if(!vis[s[i]-'a']) sum[i]++;
vis[s[i]-'a']=;
}
for(int i=;i<=n;++i) f[i][]=sum[i];
for(int i=;i<=n;++i) p[i]=;
for(int i=;i<=n;++i){
for(int j=i-;j>=;--j){
if(s[j]==s[i]) {p[i]=j;break;}
}
}
// for(int i=1;i<=n;)
// for(int i=1;i<=n;++i) cout<<sum[i]<<" ";
// for(int i=1;i<=n;++i) cout<<p[i]<<" ";
for(int i=;i<=n;++i){
for(int j=;j<=min(l,i);++j){
f[i][j]=(f[i-][j]+f[i-][j-]-f[p[i]-][j-]+mod)%mod;
}
}
/*for(int i=1;i<=n;++i){
for(int j=1;j<=min(i,l);++j){
cout<<"dp["<<i<<"]["<<j<<"]="<<f[i][j]<<endl;
// if(p[i]-1==0)cout<<f[p[i]-1][j-1]<<" ";
}
}*/
printf("%lld",f[n][l]);
}

coin

20190908 NOIP 模拟40的更多相关文章

  1. Noip模拟40 2021.8.15

    T1 送花 按照题解意思说是扫描线题,但我觉得像一个线段树优化$dp$ 主要思想一样,就是暴力枚举右端点,同时维护左端点的最值, 考虑两种情况, 如果左端点在$r$扫到的数$i$上一次出现的位置之前, ...

  2. 2021.8.15考试总结[NOIP模拟40]

    T1 送花 线段树.枚举右端点,线段树记录左端点对应的值. 每次对当前颜色上上次出现的位置到上次出现的位置区间减,上次出现的位置到当前位置区间加. $code:$ 1 #include<bits ...

  3. NOIP模拟 40

    考得更嘛也不是了. 不过如果不犯任何低错的话.. T1 我神奇地想要缩减码量 比如想把尽量多的$b[i]-1$省掉 于是求$b[i]$的时候先减了个一 本来是正的 减完就忘了他应该是非负的了 于是线段 ...

  4. noip模拟40

    \(\color{white}{\mathbb{名之以:海棠}}\) 考场 \(t1\) 看见题意非常简单,觉得可能是个简单题 暴力算出几个小样例右端点右移的时候左端点都是单调右移的,以为具有单调性, ...

  5. [考试总结]noip模拟40

    最近真的是爆炸啊... 到现在还是有不少没改出来.... 所以先写一下 \(T1\) 的题解.... 送花 我们移动右端点,之后我们用线段树维护全局最大值. 之后还要记录上次的位置和上上次的位置. 之 ...

  6. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  7. 11.7 NOIP模拟赛

    目录 2018.11.7 NOIP模拟 A 序列sequence(two pointers) B 锁lock(思路) C 正方形square(埃氏筛) 考试代码 B C 2018.11.7 NOIP模 ...

  8. NOIP模拟赛-2018.11.6

    NOIP模拟赛 今天想着反正高一高二都要考试,那么干脆跟着高二考吧,因为高二的比赛更有技术含量(我自己带的键盘放在这里). 今天考了一套英文题?发现阅读理解还是有一些困难的. T1:有$n$个点,$m ...

  9. 2016-06-19 NOIP模拟赛

          2016-06-19 NOIP模拟赛 by coolyangzc 共3道题目,时间3小时 题目名 高级打字机 不等数列 经营与开发 源文件 type.cpp/c/pas num.cpp/c ...

随机推荐

  1. mysql数据库的 varchar 和 char 的区别

    char是存储字符(无论字母还是汉字都最多存255个) char(20)表示这个字段最多存20个字符 如果存了16个字符    那么也会占用20个字符的空间 varchar是存储字节(1个字母1个字节 ...

  2. Web Server 分布式服务: Nginx负载均衡

    Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.由俄罗斯的程序设计师Igor Sysoev所开发,供俄国大型的入口网站及搜索引擎Rambler使用.其 ...

  3. S02_CH04_User_IP实验Enter a post title

    S02_CH04_User_IP实验 4.1 创建IP 在之前的教程中,我们通过MIO与EMIO来控制LED,所使用的也是官方的IP,实际当中,官方提供的IP不可能涵盖到方方面面,用户需要自己编写硬件 ...

  4. linux下的终端利器 tmux 安装以及使用

    ref :https://www.jianshu.com/p/fd3bbdba9dc9 Introduction 为什么使用tmux? 因为如果我们用terminal连接remote server.发 ...

  5. php 获取城市ip

    /** * 获取ip城市信息 * CreateBy XueSong * @param string $ip * @return array|bool|mixed */ function getCity ...

  6. python 识别图像主题并切割

    两种办法,一种是用百度的API,效果还可以,不过好像每天有50次的调用的限制 from aip import AipImageClassify import cv2 """ ...

  7. NOIP2009-2018简要题解

    口胡警告 NOIP2009 潜伏者 模拟 Hankson 的趣味题 对四个数\(a_0,a_1,b_0,b_1\)分解质因数,结果序列分别记为\(\{p1^{b1}\},\{p2^{b2}\},\{p ...

  8. hive面试题(免费拿走不谢)

    Hive 最常见的几个面试题 1.hive 的使用, 内外部表的区别,分区作用, UDF 和 Hive 优化(1)hive 使用:仓库.工具(2)hive 内部表:加载数据到 hive 所在的 hdf ...

  9. 浅谈Promise原理与应用

    在JavaScript中,所有代码都是单线程.由于该“缺陷”,JavaScript在处理网络操作.事件操作时都是需要进行异步执行的.AJAX就是一个典型的异步操作 对于异步操作,有传统的利用回调函数和 ...

  10. bash shell脚本之成员变量

    shell中变量的使用 cat test3: #!/bin/bash # testing variables days= guest="Katie" echo "$gue ...