2017-10-21离线赛总结
来源:互联网 发布:北京知豆电动汽车4s店 编辑:程序博客网 时间:2024/06/03 18:06
失分小结:
估分:240
实际分数:250
本来觉得240应该是一个挺正常的分数,但是很多人都考得不好
感觉第三题的思维还是太局限了,就算打暴力也只能想着模拟。。
考试流程:
前两题打得很顺,大概就一个小时多一点,最后一题玄学debug到考试结束 最后十分钟灵感爆发,想到80分解法。。
题解:
第一题:
应该是一个裸的前缀和题目
反正这种题打完之后对拍一般就不会出什么问题了
第二题:
个人感觉这道题是需要一些想法的。。
n<=100000
纯粹的LIS肯定过不掉,要加上些数据结构维护(像什么BIT,线段树。。)
然后就是如何知道它是1、2、3
我的方法复杂度可能有点高 纯粹是因为线段树常数大的缘故
就是正着扫一遍,反着扫一遍
像普通LIS一样求出他的dp值
大约是
然后看多少个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判定
这题的状态也比较明显,也就是第一行填到第几个,第二行填到第几个
更新也就是单纯填第一行,单纯填第二行,或者两行一起填
然后复杂度会有些爆炸。。
我考试时的复杂度是
然后优化最后一层,测评机告诉我的。。
是地球人都看得出这题的复杂度应该是
虽然后来Komachi dalao写出了
然后就加了组hack数据害人
相较于之前最愚蠢的dp转移,我们可以发现,其实没有什么必要分别枚举上下两行的状态
只用预处理最多填到哪列 然后一列一列枚举 复杂度为
讲一下Komachi的玄学写法
预处理从某点铺画最多到哪个点
然后一步一步铺过去,最多铺m幅
当然之前要枚举从第一幅后开始铺
dp[i]表示铺到第几幅最多铺到第几列
代码实现:
#include<cstdio>#include<cstring>#define FOR(i,x,y) for(int i=(x);i<=(y);i++)#define ll long longinline 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;}
- 2017-10-21离线赛总结
- 2017-10-10离线赛总结
- 2017-10-4离线赛总结
- 2017-10-6离线赛总结
- 2017-10-7离线赛总结
- 2017-10-8离线赛总结
- 2017-10-9离线赛总结
- 2017-10-12离线赛总结
- 2017-10-15离线赛总结
- 2017-10-16离线赛总结
- 2017-10-17离线赛总结
- 2017-10-18离线赛总结
- 2017-10-19离线赛总结
- 2017-10-23离线赛总结
- 2017-10-24离线赛总结
- 2017-10-26离线赛总结
- 2017-10-29离线赛总结
- 2017-10-30离线赛总结
- C++风格_变长数组和alloca()
- php curl实现图片下载
- 用Intellij IDEA和SBT建立scala时,新手容易遇到的一些麻烦
- Linux入门学习Make
- 使用更小卷积核的作用
- 2017-10-21离线赛总结
- [noip2015]斗地主 题解
- C++风格_友元
- 10.21离线赛
- Oracle之分区表和索引优化,分区表字段回表
- C++风格_异常
- Python practice
- java 中 问题及其他
- 随机产生两组整数,每组整数中元素互不相同,这两组数按值递增有序。设计程序,将这两组数合并成按值递减有序的一组数,要求合并的新的一组数中,相同的元素只有一个。