SDWC补题计划
2018的寒假去了SD的冬令营,因为一班二班难度悬殊,对我很不友好,几乎什么也没学会,但是我把两个班的课件都存了下来,现在慢慢把两个班的例题以及课后题都补一补(毕竟冬令营的钱不能白花)。
这些题目横跨各大知名题库以及一大批外国题库,以至于我注册了一批新账号......
基础班Day1:
这一天的课事实上我并没有去听,而是去二班考试并愉快的爆零了,幸好不大难,自己看也能学会。
Day1主要讲了队列,栈,堆,(加权)并查集。还提出了“因为数组也是数据结构,所以一切题目都是数据结构题”的精彩言论。
UVA514 Rails:https://www.luogu.org/problemnew/show/UVA514
题目概述:(火车,铁轨,车厢……)有一个无限大的栈,按照1-n的顺序依次入栈,询问是否能生成给定的出栈序。
栈的题目,模拟。以前练习初赛时见过这种题的手画版本...事实上也就是那个思路。如果现在想让一个数出栈,可是它还没入栈,就不停的入栈直到它入栈后再弹出;如果它已经在栈里,则必须是栈顶,否则就无法生成这个序列。这题在洛谷上难度虚高,主要是读入很奇妙;输出时如果n将要变化了,要换行,样例里却没换,导致很容易wa。
# include <cstdio> # include <iostream> # include <cstring> using namespace std; int n; int a[1005],sta[1005],h=0,q=0,s=0; int main() { scanf("%d",&n); while (n) { memset(a,1,sizeof(a)); scanf("%d",&a[1]); while (a[1]!=0) { for (int i=2;i<=n;i++) scanf("%d",&a[i]); q=s=1; h=0; for (int i=1;i<=n;++i) { while(s<=a[i]) sta[++h]=s++; while(sta[h]==a[q]) q++,h--; } if(s!=n+1||h!=0||q!=n+1) printf("No\n"); else printf("Yes\n"); scanf("%d",&a[1]); } printf("\n"); scanf("%d",&n); } return 0; }
NOI2001 食物链:https://www.luogu.org/problemnew/show/P2024
题目概述:有三种动物,食物关系竟然形成了一个环(好不科学啊),给出一些描述:A被B吃,A吃B,A与B是同类,默认先说的话是正确的,并以此判断一共有几句假话。
这大概是加权并查集最著名的习题了,也可以不用加权做,注意一下加权并查集的路径压缩,还是挺容易写错的。(做完这个题,你的并查集就算入门了---loli)
int father(int x) { if (x!=f[x]) { int aa=father(f[x]); v[x]=(v[x]+v[f[x]])%3; f[x]=aa; } return f[x]; }
有一个地方一定要想清楚,在同一个并查集里的元素并不一定是同种生物,只是可以确定相对的关系,如果这里明白了也就比较简单了。
带权并查集的集合合并也别写错啦...就是解一个方程。
# include <cstdio> # include <iostream> using namespace std; int f[50005]={0},v[50005]={0}; int n,k,x,y,z,S=0; int father(int x) { if (x!=f[x]) { int aa=father(f[x]); v[x]=(v[x]+v[f[x]])%3; f[x]=aa; } return f[x]; } bool Ya(int x,int y,int z) { int a=father(y); int b=father(z); if (a==b) { if(x==1) { if(v[y]==v[z]) return true; return false; } if (x==2) { if(v[z]-v[y]!=-2&&v[z]-v[y]!=1) return false; return true; } } if (a!=b) { if(x==1) { v[b]=(v[y]-v[z]+3)%3; f[b]=a; } if (x==2) { v[b]=(v[y]-v[z]+4)%3; f[b]=a; } return true; } } int main() { scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) { f[i]=i; v[i]=0; } for (int i=1;i<=k;i++) { scanf("%d%d%d",&x,&y,&z); if (z>n||y>n) S++; else if (y==z&&x==2) S++; else if (Ya(x,y,z)==false) S++; } printf("%d",S); return 0; }
合并果子:https://www.luogu.org/problemnew/show/P1090
题意概述:合并两堆果子的代价是两堆重量之和,要求将n堆果子合并成一堆,求最小代价。
贪心的想一想发现每次选最小的两堆合并就是最优的。用堆是可以的,也可以用两个队列:首先排序作为第一个队列,每次新合并出来的放进第二个队列末尾,两个队列都是单调的,如果再用一个桶排序就可以达到$O(N)$,但是懒得写...
1 # include <cstdio> 2 # include <iostream> 3 4 using namespace std; 5 6 int a,H[20003]={0},r=0,n,po,M,t; 7 8 void push(int x) 9 { 10 po=++r; 11 while(x<H[po/2]) 12 { 13 H[po]=H[po/2]; 14 po=po/2; 15 } 16 H[po]=x; 17 } 18 19 void Heapify(int x) 20 { 21 M=x; 22 if (r>=x*2+1&&H[M]>H[x*2+1]) M=x*2+1; 23 if (r>=x*2&&H[M]>H[x*2]) M=x*2; 24 if (M!=x) 25 { 26 t=H[x]; 27 H[x]=H[M]; 28 H[M]=t; 29 Heapify(M); 30 } 31 } 32 33 void pop() 34 { 35 if (r==1) 36 { 37 H[1]=0; 38 r=0; 39 return; 40 } 41 H[1]=H[r--]; 42 Heapify(1); 43 } 44 45 int main() 46 { 47 int x,y,S=0; 48 scanf("%d",&n); 49 for (int i=1;i<=n;i++) 50 { 51 scanf("%d",&a); 52 push(a); 53 } 54 for (int i=1;i<n;i++) 55 { 56 x=H[1]; pop(); 57 y=H[1]; pop(); 58 S+=x+y; 59 push(x+y); 60 } 61 cout<<S; 62 return 0; 63 }
蚯蚓:https://www.luogu.org/problemnew/show/P2827
题意概述:有n根蚯蚓,每次选出一根最长的切成给定比例的两段,同时其他的蚯蚓长度增加一个常数,求每次被切断的蚯蚓长度。
首先可以反着想,认为是被剪了的蚯蚓长度减少一个常数,就可以用堆维护了,听起来非常棒,而且很符合今天的上课内容,然而T掉了。那么正解是什么呢?和上一道题一样,又是队列...因为我们是用缩短长度的做法做的,所以每次取出的最长蚯蚓的长度是单调递减的,又因为比例相同,所以切成的两段也是递减的,所以就是三个递减的队列了。
1 # include <cstdio> 2 # include <iostream> 3 # include <algorithm> 4 # include <cstring> 5 # define R register int 6 7 using namespace std; 8 9 int h_1=1,t_1=1,h_2=1,t_2=0,h_3=1,t_3=0,n,m,q,t; 10 long long x_1,x_2,x,u,v; 11 long long q_1[500009],q_2[10000009],q_3[10000009],ans; 12 const int inf=-1e8; 13 14 bool cmp(long long a,long long b) 15 { 16 return a>b; 17 } 18 19 int main() 20 { 21 scanf("%d%d%d%lld%lld%d",&n,&m,&q,&u,&v,&t); 22 memset(q_1,128,sizeof(q_1)); 23 memset(q_2,128,sizeof(q_2)); 24 memset(q_3,128,sizeof(q_3)); 25 for (R i=1;i<=n;++i) 26 scanf("%lld",&q_1[i]); 27 sort(q_1+1,q_1+1+n,cmp); 28 for (R i=1;i<=m;++i) 29 { 30 if(q_1[h_1]>=q_2[h_2]&&q_1[h_1]>=q_3[h_3]) 31 x=q_1[h_1++]; 32 else if(q_2[h_2]>=q_1[h_1]&&q_2[h_2]>=q_3[h_3]) 33 x=q_2[h_2++]; 34 else if(q_3[h_3]>=q_2[h_2]&&q_3[h_3]>=q_1[h_1]) 35 x=q_3[h_3++]; 36 x=x+(i-1)*q; 37 if(i%t==0) printf("%lld ",x); 38 x_1=u*x/v; 39 x_2=x-x_1; 40 q_2[++t_2]=x_1-i*q; 41 q_3[++t_3]=x_2-i*q; 42 } 43 printf("\n"); 44 for (R i=1;i<=n+m;++i) 45 { 46 if(q_1[h_1]>=q_2[h_2]&&q_1[h_1]>=q_3[h_3]) 47 ans=q_1[h_1++]; 48 else if(q_2[h_2]>=q_1[h_1]&&q_2[h_2]>=q_3[h_3]) 49 ans=q_2[h_2++]; 50 else if(q_3[h_3]>=q_2[h_2]&&q_3[h_3]>=q_1[h_1]) 51 ans=q_3[h_3++]; 52 if(i%t==0) printf("%lld ",ans+m*q); 53 } 54 return 0; 55 }
Largest Rectangle in a Histogram:http://poj.org/problem?id=2559
Open Gold - Trapped in the Haybales:https://www.lydsy.com/JudgeOnline/problem.php?id=4099
这在bzoj上是个权限题,usaco上肯定有,然而我找不到。。。下次借个权限号做。
基础班Day2:我把课件弄丢啦!!有好心人给我一份吗!
基础班Day3:
深搜、广搜,虽然是基础算法但是也有不少难题呢。
基础班Day4:
贪心,dp。
基础班Day5:
数论,倍增。
基础班Day6:
线段树与树状数组。
提高班Day1:
线段树,主席树。
提高班Day2:
数论。
提高班Day3:
计算几何。
提高班Day4:
动规及优化。
提高班Day5:
Splay,Lct,链剖,网络流,图论题目选讲。
提高班Day6:(老师跑路了没上课)
补完这些还有每天的考试题,也都是很好的题,感觉任务艰巨。
---shzr