HHHOJ #1242. 「NOIP 2023 模拟赛 20230713 D」星海巡航 总结与思考--zhengjun
随机排列的最长上升子序列长度的期望是 。
这个结论知道最好,不知道也问题不大,赛时随一个跑一下也行。
警告:
-
一直考虑正着做,产生了思维定式
-
正难则反啊,反着做发现只需考虑第一次覆盖的数就行了。
-
接下来的贪心也没想到:序列中不应该出现不在 中的数( 除外),否则删掉他,可以使序列长度减少,跨越序列的代价就减少了。
-
然后就是 dp,转移发现上个树状数组优化即可。
时间复杂度:,空间复杂度:
最后讲一下卡常的点:
-
开 short
-
枚举 长度时,如果当前 dp 值为 ,那么就可以 break 了(注意要在 > 2 时才满足这个性质)
代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const short N=1.5e4+10,INF=N*2,M=3e2+10;
short n,a[N];
short f[N][M],g[N][M];
struct BIT1{
short c[N];
void init(){
memset(c,0x7f,sizeof c);
}
void add(short x,short y){
for(;x&&c[x]>y;x^=x&-x)c[x]=y;
}
void get(short x,short &y){
for(;x<=n;x+=x&-x)c[x]<y&&(y=c[x]);
}
}F[M];
struct BIT2{
short c[N];
void init(){
memset(c,-0x7f,sizeof c);
}
void add(short x,short y){
for(;x<=n&&c[x]<y;x+=x&-x)c[x]=y;
}
void get(short x,short &y){
for(;x;x^=x&-x)c[x]>y&&(y=c[x]);
}
}G[M];
struct opts{
short x,y,z;
};
vector<opts>oF[N],oG[N];
short ans=0;
void init(){
memset(f,0x7f,sizeof f),memset(g,-0x7f,sizeof g);
memset(F,0x7f,sizeof F),memset(G,-0x7f,sizeof G);
for(short i=1;i<=n;i++)oF[i].clear(),oG[i].clear();
}
short st;
void ins(short i){
for(short x=st;x+1<M;x++){
if(x>2&&f[i][x]>=INF)break;
F[x+1].add(a[i]-1,f[i][x]);
if(i>x)oF[i-x].push_back({short(x+1),f[i][x],a[i]});
}
for(short x=st;x+1<M;x++){
if(x>2&&g[i][x]<=-INF)break;
G[x+1].add(a[i]+1,g[i][x]);
if(i>x)oG[i-x].push_back({short(x+1),g[i][x],a[i]});
}
}
//bool cmp(opts x,opts y){
// return x.x<y.x;
//}
void trs(short i){
// sort(oF[i].begin(),oF[i].end(),cmp);
// sort(oG[i].begin(),oG[i].end(),cmp);
for(opts x:oF[i]){
G[x.x].add(x.y+1,x.z);
}
for(opts x:oG[i]){
F[x.x].add(x.y-1,x.z);
}
for(short x=st;x<M;x++){
F[x].get(a[i],f[i][x]);
if(x>2&&f[i][x]>=INF)break;
}
for(short x=st;x<M;x++){
G[x].get(a[i],g[i][x]);
if(x>2&&g[i][x]<=-INF)break;
}
}
void solve1(){
st=1;
init();
f[n][1]=g[n][1]=a[n];
for(short i=n-1;i>=1;i--){
ins(i+1);
trs(i);
}
for(short i=M-1;i>=1;i--)for(short j=1;j<=n;j++)
if(f[j][i]<INF||g[j][i]>-INF){
ans=max(ans,i);
return;
}
}
void solve2(){
st=2;
init();
for(short i=n-1;i>=1;i--){
ins(i+1);
f[i][2]=min(f[i][2],a[i]);
g[i][2]=max(g[i][2],a[i]);
trs(i);
}
for(short i=M-2;i>=1;i--)for(short j=1;j<=n;j++)
if(f[j][i+1]<INF||g[j][i+1]>-INF){
ans=max(ans,i);
return;
}
}
void read(short &x){
char c;
for(x=0;!isdigit(c=getchar()););
for(;x=(x<<3)+(x<<1)+(c^48),isdigit(c=getchar()););
}
int main(){
read(n);
for(short i=1;i<=n;i++)read(a[i]);
solve1();
solve2();
cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!