二调考试总结
爆零经过
文化课二调也结束了,果然都炸了呢(麻木)
来了之后立刻被告知要考试,不分AB层了有点震惊,虽然我这个B层蒟蒻已经做好了被吊打的准备
先看题,T1到T3都挺眼熟,然而看着又都不太可做……
T1很快看出来是树形dp,分组背包模型,但是板子基本不记得,于是先做的T2
T2看出来是线性dp的lcs板子,但是又双叒叕忘了,只想起了lis的大体步骤,于是考虑了一个预处理把lcs转成lis,然后用lis去做,然而我转的有问题,方法又奇怪又没正确性,然后我就傻乎乎的用lis去做了,碰巧样例水给过了,然后就直接交了就没理,事后发现我是第一个交的,WA,0,嘎
然后回来做第一题,由于当时刚学的时候只有我和WYZG用了背包,所以看着旁边人都在刚,意识到有点难,但还想试试,想了想先建树,结果遇到沙雕问题,vector忘了咋拼,结果我调出了五六个stl库,最后的发现没写int ,有点搞心态。。。
由于以前有过建树(三色二叉)的经验,建树挺顺利,然后凭着自己的记忆边推边写树形dp,过了快一个小时写差不多了,结果发现样例过不去……
剩一个小时,周围人基本弃掉T1了,我还在一直调……看了看T3,正解想不出来,觉得暴力顶多拿十几分,就没打暴力,一直在调第一个,结果到了时间也没改出来,于是T1交了没过测试点的代码,T3直接输出了0
成绩一出,爆零,刺激
T1竟然CE了,万能库加了个".",直接没过编译,本地竟然没编译出来,炸裂*1;
T2也炸了,发现不少人都打出了60分dp,本来以为是个水题,结果还是自己太弱了,炸裂*2;
T3纯暴力竟然有50分,枯了,炸裂*3;
OI路漫漫,积攒经验吧……
T1 偷天换日
就个树形dp,后来发现中间少循环了一层
建了树之后直接跑树形背包就行,理解了打出来就没问题
注意非叶子节点边权双倍,还有最后是求n-1时刻的状态,因为n秒警察就来了会被抓
数组比较玄学,要仔细看题,不然会re,最多300个房间,每个房间最多300副画,所以我开的是9000数组
T2 基因匹配
首先就是基本线性dp,lcs能搞60分,需要优化
主要有两个优化方案
第一是我的做法,由于每个数字出现5次固定,先预处理出第二串每个数字的位置(有5个)存起来,再将第一串数字每个数字都替换成该数字对应的那5个数字,这样一来,把lcs成功变成了lis,正确性在于首先循环保证了第一串的有序,替换数字要从后往前,比如1出现在1,3,4,5,6,就把他替换成6,5,4,3,1,搞一个上升子序列(这样保证每个数字最多选一次,如果是13456就会选5次),把每个都替换成对面的数字这个过程保证了第二串实际上也是有序的,把字符匹配这个过程转化成了根据字符出现位置来找单纯子序列,这样空间复杂度就降下来了,一维就够
这还是n2,要搞nlogn,可以二分栈,把答案视作一个栈,他是单调递增的,每次如果这个数字比栈顶(最大的)小,就二分找到大于等于他的第一个数替换掉,比栈顶大直接入栈,本质是把第二轮枚举变成了二分,元素个数就是序列长,搞定
还有就是用lcs做,由于每次转移只有5个可行的状态可能转移,就可以把他们存起来,然后每次读入更新一次,用树状数组优化
个人觉得第一种更通用一些,收获是学会了两种线性dp优化方式,还有lis和lcs转换
T3 旅馆
线段树区间合并,这题暴力竟然能过是受不了的,lrx强者加强了一波数据,卡掉了暴力
就是一个区间,要么0要么1,询问一定个数的0,以及修改,可以用线段树维护
维护几个东西:区间长度(l,r),最大0个数,分别从左,右开始最大0的个数(因为转移要用到),懒惰标记(修改用)
区间0个数就是两个子树里的最大0个数,和左子树从右边开始0个数加上右子树从左开始0个数,这三个的最大值
左右最大0个数用if判断一下,能更新则更新,想一下就好了
修改的时候注意有两种操作,一个是全变成0一个是全变成1,0的话就把三个变量都变成0,1的话就把三个变量都变成区间长度(不要习惯设成一,我在这里卡过),就是r-l+1,别的都和基本线段树差不多,然后就是重新维护,和建树里的维护操作差不多
懒惰标记要设成两种情况,初始化-1,0和1分别代表两个修改操作,每次修改之前都要下放标记,细节要注意
代码在这,留着自己看
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct tr{ 4 int c; 5 int v; 6 vector <int>sb; 7 }a[9005]; 8 int num=1,f[9005][1005]; 9 void bt() 10 { 11 int t,x;int id=num; 12 scanf("%d%d",&t,&x); 13 a[id].c=2*t; 14 if(x==0) 15 { 16 a[id].sb.push_back(++num); 17 bt(); 18 a[id].sb.push_back(++num); 19 bt(); 20 } 21 if(x!=0) 22 for(int i=1;i<=x;i++) 23 { 24 int w,cc; 25 scanf("%d%d",&w,&cc); 26 a[id].sb.push_back(++num); 27 a[num].v=w;a[num].c=cc; 28 } 29 } 30 int dp(int id,int n) 31 { 32 if(a[id].sb.size()==0) 33 { 34 for(int i=a[id].c;i<=n;i++) 35 f[id][i]=a[id].v; 36 return f[id][n]; 37 } 38 for(int i=1;i<=a[id].sb.size();i++) 39 { 40 dp(a[id].sb[i-1],n); 41 for(int j=n;j>=0;j--) 42 for(int k=0;k<=j;k++) 43 { 44 f[id][j]=max(f[id][j],f[id][j-k]+f[a[id].sb[i-1]][k]); 45 } 46 } 47 for(int j=n;j>=0;j--)f[id][j]=f[id][j-a[id].c]; 48 return f[id][n]; 49 } 50 int main() 51 { 52 int n; 53 cin>>n; 54 bt(); 55 // for(int i=1;i<=num;i++) 56 // cout<<a[i].c<<" "<<a[i].v<<" "<<a[i].sb.size()<<endl; 57 cout<<dp(1,n-1); 58 return 0; 59 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 int a[100005],b[100005],s; 4 int c[500050],m; 5 vector <int> p[100005]; 6 int sb[500050],h,t; 7 void add(int i) 8 { 9 for(int j=4;j>=0;j--) 10 { 11 c[++m]=p[i][j]; 12 } 13 } 14 int main() 15 { 16 int n; 17 cin>>n; 18 for(int i=1;i<=5*n;i++) 19 scanf("%d",&a[i]); 20 for(int i=1;i<=5*n;i++) 21 scanf("%d",&b[i]); 22 for(int i=1;i<=5*n;i++) 23 p[b[i]].push_back(i); 24 for(int i=1;i<=5*n;i++) 25 add(a[i]);//化lcs为lis 26 for(int i=1;i<=m;i++) 27 { 28 if(h==t)sb[++t]=c[i]; 29 else 30 { 31 if(c[i]>sb[t])sb[++t]=c[i]; 32 else 33 { 34 int q=lower_bound(sb+h+1,sb+t+1,c[i])-sb; 35 sb[q]=c[i];///二分栈 36 } 37 } 38 s=max(s,t-h); 39 } 40 cout<<s; 41 return 0; 42 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct tr{ 4 int l,r; 5 int l0,r0;//从左右开始的最长连续房间 6 int lazy=-1;//懒惰标记同时支持增加和减小,初始成特值 7 int s;//区间内的最长连续房间 8 }a[200050]; 9 void js(int id,int l,int r) 10 { 11 a[id].l=l;a[id].r=r; 12 if(l==r) 13 { 14 a[id].s=1; 15 a[id].l0=1;a[id].r0=1; 16 return ; 17 } 18 int mid=(l+r)/2; 19 js(id*2,l,mid); 20 js(id*2+1,mid+1,r); 21 a[id].s=max(max(a[id*2].s,a[id*2+1].s),a[id*2].r0+a[id*2+1].l0);//区间总长从子树里选最大的 22 if(a[id*2].s==a[id*2].r-a[id*2].l+1)a[id].l0=a[id*2].s+a[id*2+1].l0;//分别更新左右连续房间 23 else a[id].l0=a[id*2].l0; 24 if(a[id*2+1].s==a[id*2+1].r-a[id*2+1].l+1)a[id].r0=a[id*2].r0+a[id*2+1].s; 25 else a[id].r0=a[id*2+1].r0; 26 } 27 void luo(int id) 28 { 29 if((a[id].lazy==1)&&(a[id].l!=a[id].r))//整个区间全满,都是0 30 { 31 a[id*2].s=0;a[id*2+1].s=0; 32 a[id*2].l0=0;a[id*2+1].l0=0; 33 a[id*2].r0=0;a[id*2+1].r0=0; 34 a[id*2].lazy=1;a[id*2+1].lazy=1; 35 a[id].lazy=-1; 36 } 37 if((a[id].lazy==0)&&(a[id].l!=a[id].r))//全退,都是区间长度 38 { 39 a[id*2].s=a[id*2].r-a[id*2].l+1;a[id*2+1].s=a[id*2+1].r-a[id*2+1].l+1; 40 a[id*2].l0=a[id*2].r-a[id*2].l+1;a[id*2+1].l0=a[id*2+1].r-a[id*2+1].l+1; 41 a[id*2].r0=a[id*2].r-a[id*2].l+1;a[id*2+1].r0=a[id*2+1].r-a[id*2+1].l+1; 42 a[id*2].lazy=0;a[id*2+1].lazy=0; 43 a[id].lazy=-1; 44 } 45 } 46 int cha(int id,int l,int r,int len) 47 { 48 luo(id); 49 if(a[id].s<len)return 0;//不行输出0 50 int mid=(l+r)/2; 51 if(a[id*2].s>=len)return cha(id*2,l,mid,len);//注意顺序,优先从左到右 52 if(a[id*2].r0+a[id*2+1].l0>=len)return mid-a[id*2].r0+1; 53 return cha(id*2+1,mid+1,r,len); 54 } 55 void gan(int id,int l,int r,int x) 56 { 57 luo(id);//无论加或减都要先下穿标记,避免还没传就更新了出错 58 if(x==0)//入住 59 { 60 if(a[id].l>=l&&a[id].r<=r) 61 { 62 a[id].s=0;a[id].l0=0;a[id].r0=0; 63 a[id].lazy=1; 64 return ; 65 } 66 int mid=(a[id].l+a[id].r)/2;//类似区间修改 67 if(mid>=r||mid<l) 68 { 69 if(mid>=r)gan(id*2,l,r,x); 70 if(mid<l)gan(id*2+1,l,r,x); 71 } 72 else 73 { 74 gan(id*2,l,mid,x); 75 gan(id*2+1,mid+1,r,x); 76 } 77 a[id].s=max(max(a[id*2].s,a[id*2+1].s),a[id*2].r0+a[id*2+1].l0);//合并维护,跟建树时一样 78 if(a[id*2].s==a[id*2].r-a[id*2].l+1)a[id].l0=a[id*2].s+a[id*2+1].l0; 79 else a[id].l0=a[id*2].l0; 80 if(a[id*2+1].s==a[id*2+1].r-a[id*2+1].l+1)a[id].r0=a[id*2].r0+a[id*2+1].s; 81 else a[id].r0=a[id*2+1].r0; 82 } 83 if(x==1)//退房 84 { 85 if(a[id].l>=l&&a[id].r<=r) 86 { 87 a[id].s=a[id].r-a[id].l+1;//注意这里不是1,由于退房所以整个区间都是0,是区间最大长度 88 a[id].l0=a[id].r-a[id].l+1;a[id].r0=a[id].r-a[id].l+1; 89 a[id].lazy=0; 90 return ; 91 } 92 int mid=(a[id].l+a[id].r)/2; 93 if(mid>=r||mid<l) 94 { 95 if(mid>=r)gan(id*2,l,r,x); 96 if(mid<l)gan(id*2+1,l,r,x); 97 } 98 else 99 { 100 gan(id*2,l,mid,x); 101 gan(id*2+1,mid+1,r,x); 102 } 103 a[id].s=max(max(a[id*2].s,a[id*2+1].s),a[id*2].r0+a[id*2+1].l0); 104 if(a[id*2].s==a[id*2].r-a[id*2].l+1)a[id].l0=a[id*2].s+a[id*2+1].l0; 105 else a[id].l0=a[id*2].l0; 106 if(a[id*2+1].s==a[id*2+1].r-a[id*2+1].l+1)a[id].r0=a[id*2].r0+a[id*2+1].s; 107 else a[id].r0=a[id*2+1].r0;//同上 108 } 109 } 110 int main() 111 { 112 int n,m; 113 cin>>n>>m; 114 js(1,1,n); 115 for(int i=1;i<=m;i++) 116 { 117 int x; 118 scanf("%d",&x); 119 if(x==1) 120 { 121 int y; 122 scanf("%d",&y); 123 int z=cha(1,1,n,y); 124 if(z==0)printf("0\n"); 125 else{ 126 printf("%d\n",z); 127 gan(1,z,z+y-1,0); 128 } 129 } 130 if(x==2) 131 { 132 int y,z; 133 scanf("%d%d",&y,&z); 134 gan(1,y,y+z-1,1); 135 } 136 } 137 return 0; 138 } 139 //在普通线段树上增加区间合并,维护的东西不太一样 140 //每次操作维护就是一个区间合并的过程,标记下传分类 141 //复杂度nlogn
反思
1.暴力分要拿到,不要完全弃掉某道题,不要死肝正解
2.板子还得背
3.心态要好,不要被周围人影响
4.避免各种沙雕低级失误,敲代码时候慢点

浙公网安备 33010602011771号