2017-10-21离线赛总结

本文回顾了一次编程比赛经历,并详细解析了三道题目的解题思路与代码实现过程,重点介绍了利用前缀和、线段树等数据结构优化最长递增子序列问题的方法及一道涉及二维动态规划的问题。

失分小结:
估分:240
实际分数:250
本来觉得240应该是一个挺正常的分数,但是很多人都考得不好
感觉第三题的思维还是太局限了,就算打暴力也只能想着模拟。。

考试流程:
前两题打得很顺,大概就一个小时多一点,最后一题玄学debug到考试结束
最后十分钟灵感爆发,想到80分解法。。

题解:
第一题:
应该是一个裸的前缀和题目
反正这种题打完之后对拍一般就不会出什么问题了
第二题:
个人感觉这道题是需要一些想法的。。
n<=100000
纯粹的LIS肯定过不掉,要加上些数据结构维护(像什么BIT,线段树。。)
然后就是如何知道它是1、2、3
我的方法复杂度可能有点高 纯粹是因为线段树常数大的缘故
就是正着扫一遍,反着扫一遍
像普通LIS一样求出他的dp值
大约是dp1[i]+dp2[i]+1==ans 时说明这个点在LIS上
然后看多少个dp[i]相同,若这个dp[i]是唯一的
那么这个点必须出现在LIS上

代码实现:

int A[M],B[M];
int Sum1[M],Sum2[M];
bool mark[M];
int Cnt[M];
struct Tree{
    int l,r,sum;
}tree[M<<2];
void build(int l,int r,int p){
    tree[p].l=l,tree[p].r=r,tree[p].sum=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(l,mid,p<<1);
    build(mid+1,r,p<<1|1);
}
void update(int x,int a,int p){
    if(tree[p].l==tree[p].r){
        tree[p].sum=Max(tree[p].sum,a);
        return;
    }
    int mid=(tree[p].l+tree[p].r)>>1;
    if(mid>=x)update(x,a,p<<1);
    else update(x,a,p<<1|1);
    tree[p].sum=Max(tree[p<<1].sum,tree[p<<1|1].sum);
}
int query(int l,int r,int p){
    if(tree[p].l==l&&tree[p].r==r){
        return tree[p].sum;
    }
    int mid=(tree[p].l+tree[p].r)>>1;
    if(mid>=r)return query(l,r,p<<1);
    else if(mid<l)return query(l,r,p<<1|1);
    else return Max(query(l,mid,p<<1),query(mid+1,r,p<<1|1));
}
int main(){

    int n;
    scanf("%d",&n);
    FOR(i,1,n)scanf("%d",&A[i]),B[i]=A[i];
    sort(B+1,B+n+1);
    int len=unique(B+1,B+n+1)-B-1;
    build(1,len,1);
    FOR(i,1,n){
        int id=lower_bound(B+1,B+len+1,A[i])-B;
        int mx=0;
        if(id>1){
            mx=query(1,id-1,1);
            Sum1[i]=mx;
        }
        update(id,mx+1,1);
    }
    int tmp=query(1,len,1);
    build(1,len,1);
    DOR(i,n,1){
        int id=lower_bound(B+1,B+len+1,A[i])-B;
        int mx=0;
        if(id<len){
            mx=query(id+1,len,1);
            Sum2[i]=mx;
        }
        update(id,mx+1,1);
    }
    FOR(i,1,n){
        if(Sum1[i]+Sum2[i]+1!=tmp)continue;
        mark[i]=1;
        Cnt[Sum1[i]]++;
    }
    FOR(i,1,n){
        if(!mark[i])printf("1");
        else {
            if(Cnt[Sum1[i]]==1)printf("3");
            else printf("2");
        }
    }
    return 0;
}

第三题:
考试时yy这题肯定是二分加dp判定
这题的状态也比较明显,也就是第一行填到第几个,第二行填到第几个
更新也就是单纯填第一行,单纯填第二行,或者两行一起填
然后复杂度会有些爆炸。。
我考试时的复杂度是O(logSn3m) 只能过二十分的数据
然后优化最后一层,O(logSlognn2m)能卡到50分 测评机告诉我的。。
是地球人都看得出这题的复杂度应该是O(logSnm)
虽然后来Komachi dalao写出了O(logSm2)的解法
然后就加了组hack数据害人
相较于之前最愚蠢的dp转移,我们可以发现,其实没有什么必要分别枚举上下两行的状态
只用预处理最多填到哪列 然后一列一列枚举 复杂度为O(logSnm)

讲一下Komachi的玄学写法
预处理从某点铺画最多到哪个点
然后一步一步铺过去,最多铺m幅
当然之前要枚举从第一幅后开始铺
dp[i]表示铺到第几幅最多铺到第几列

代码实现:

#include<cstdio>
#include<cstring>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define ll long long
inline void chk_mx(int &x,int y){if(x<y)x=y;}
inline int min(int x,int y){return x<y?x:y;}
//O(m*m*logS)
int A[3][20005];
int n,m;
int Nxt[3][20005],W[105];
void init(int a,int mx){
    int l=1,r=1;
    while(l<=n){
        while(r<=n&&A[a][r]-A[a][l-1]<=mx)r++;  //l->r
        Nxt[a][l]=r-1;
        l++;
    }
}
bool DP(int mx){
    memset(Nxt,0,sizeof(Nxt));
    memset(W,0,sizeof(W));
    FOR(i,0,2)init(i,mx);
    FOR(i,0,m-1){
        int a=Nxt[0][W[i]+1],b=Nxt[1][W[i]+1];
        chk_mx(W[i+1],Nxt[2][W[i]+1]);
        int cnt=i+2;
        while(cnt<=m){
            chk_mx(W[cnt],min(a,b));
            if(W[cnt]==n)return 1;
            if(a<b)a=Nxt[0][a+1];
            else b=Nxt[1][b+1];
            cnt++;
        }
    }
    return W[m]==n;
}
int main() {
    scanf("%d%d",&n,&m);
    int l=0,r=0,res=0;
    FOR(k,0,1)FOR(i,1,n){
        scanf("%d",&A[k][i]);
        if(l<A[k][i])l=A[k][i];
        r+=A[k][i];
    }
    FOR(i,0,1)FOR(j,1,n+1)A[i][j]+=A[i][j-1];
    FOR(i,1,n+1)A[2][i]=A[0][i]+A[1][i];
    while(l<=r){
        int mid=(l+r)>>1;
        if(DP(mid))r=mid-1,res=mid;
        else l=mid+1;
    }
    printf("%d\n",res);
    return 0;
}
乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值