清北學堂Day3
Part1--模擬題
今天的模擬題簡直全面爆炸。一共才拿了30分。
第一題原來做過一道差不多的。然後我就仗著自己聽過一遍正解瞎寫。嗯,就是根本沒有認真想一下這麽寫下去會不會有什麽問題。結果……
第二題拿了20。老師本來說是要用線段樹才能正解,然後我想哦那我也正解不了,心中有了一絲絲的寬慰。後來老師又想到了一種不用線段樹的做法。而且我發現這個做法和我的想法很像啊!就有一點點我沒考慮到。於是特別的氣憤。
第一題:
括號序列(bracket)
Time Limit:1000ms Memory Limit:128MB
題目描述
LYK有一個括號序列,但這個序列不一定合法。
一個合法的括號序列如下:
()是合法的括號序列。
若A是合法的括號序列,則(A)是合法的括號序列。
若A和B分別是合法的括號序列,則AB是合法的括號序列。
LYK想通過盡可能少的操作將這個不一定合法的括號序列變成合法的括號序列。一次修改操作是將某個字符變成另一個字符。
你能幫幫它嗎?
輸入格式(bracket.in)
一行一個字符串S。
輸出格式(bracket.out)
一個數表示最少修改次數。
輸入樣例
()))
輸出樣例
1
樣例解釋
將第二個字符修改成(即可。
數據範圍
對於30%的數據|S|<=10。
對於60%的數據|S|<=1000。
對於100%的數據|S|<=100000。且|S|是偶數。
先附上我的錯誤代碼:
1aWA#include <iostream> 2 #include <cmath> 3 #include <cstring> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <algorithm> 7 using namespace std; 8 char s[101010]; 9 int a[101010]; 10 int main() 11 { 12 13 freopen("bracket.in","r",stdin); 14 freopen("bracket.out","w",stdout); 15 16 scanf("%s",s); 17 for(int i=0;i<strlen(s);i++) 18 { 19 if(s[i]==‘(‘) a[i+1]=1; 20 if(s[i]==‘)‘) a[i+1]=-1; 21 } 22 for(int i=1;i<=strlen(s);i++) 23 { 24 if(a[i]<0) continue; 25 for(int j=strlen(s);j>i;j--) 26 { 27 if(a[j]>0) continue; 28 a[i]=0;a[j]=0; 29 break; 30 } 31 } 32 int ans=0; 33 for(int i=1;i<=strlen(s);i++) 34 { 35 if(a[i]!=0) ans++; 36 } 37 printf("%d",ans/2); 38 return 0; 39 }
一組錯誤答案:
正確答案應該是2。
也就是說,我的代碼沒有考慮到)( 、)))((([即有奇數組完全相反的括號]的情況
我的第二個循環結束後,對於這種情況沒有進行任何操作。
然而手算就可以知道,)))(((這種情況需要改變4次而不是3次,因此不能直接/2
下面放上標程:
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <iostream> 6 #include <string> 7 #include <cstring> 8 using namespace std; 9 char s[100005]; 10 int i,p,o,ans; 11 int main() 12 { 13 freopen("bracket.in","r",stdin); 14 freopen("bracket.out","w",stdout); 15 scanf("%s",s); p=strlen(s); 16 for (i=0; i<p; i++) 17 { 18 if (s[i]==‘)‘) 19 { 20 if (o==0){o++; ans++;} else 21 o--; 22 } 23 else 24 o++; 25 } 26 cout<<ans+o/2; 27 // system("pause"); 28 return 0; 29 }astd
簡單來說,標程的思路是:
從左往右掃過來,遇到一個‘)’,觀察前面有沒有‘(’。若有則抵消掉,否則把這個字符變成‘(’一直這麽做,掃完整個字符串之後一定剩下一堆左括號。把剩下的括號總數/2
總結:這道題就是很簡單的一道題,只不過受了之前思路的影響,導致想偏了。這告訴我以後看到熟悉的題不能上來就寫,更應該仔細思考其中的差異。
第二題:
公交車(bus)
Time Limit:1000ms Memory Limit:128MB
題目描述
LYK在玩一個遊戲。
有k群小怪獸想乘坐公交車。第i群小怪獸想從xi出發乘坐公交車到yi。但公交車的容量只有M,而且這輛公交車只會從1號點行駛到n號點。
LYK想讓小怪獸們盡可能的到達自己想去的地方。它想知道最多能滿足多少小怪獸的要求。
當然一群小怪獸沒必要一起上下車,它們是可以被分開來的。
輸入格式(bus.in)
第一行三個數k,n,M。
接下來k行每行3個數xi,yi和ci。其中ci表示第i群小怪獸的小怪獸數量。
輸出格式(bus.out)
一個數表示最多有多少只小怪獸能滿足要求。
輸入樣例
3 5 3
1 3 4
3 5 2
1 5 3
輸出樣例
5
樣例解釋
第一群的3只小怪獸在1號點上車,並在3號點下車。
第二群的2只小怪獸在3號點上車,5號點下車。
數據範圍
對於30%的數據小怪獸的總數不超過10只,n<=10。
對於另外30%的數據k,n<=1000。
對於100%的數據1<=n<=20000,1<=k<=50000,1<=M<=100,1<=ci<=100,1<=xi<yi<=n。
我的想法:首先,把輸入的小怪獸按照上車順序、下車順序和在車上呆的時間排序(具體可以看代碼)。之後從1~n掃一遍,能上車的上,容量滿了就跳過,知道有小怪獸下車,騰出容量
我的代碼:
1 #include <iostream> 2 #include <cmath> 3 #include <cstring> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <algorithm> 7 #include <queue> 8 using namespace std; 9 10 struct data 11 { 12 int x,y,c; 13 bool operator <(const data&o)const 14 {/**/ 15 if(x<o.x) return true; 16 else if(x==o.x && y<o.y) return true; 17 else if(x==o.x && y==o.y && c>o.c) return true; 18 else return false; 19 } 20 }a[20101]; 21 22 int main() 23 { 24 25 freopen("bus.in","r",stdin); 26 freopen("bus.out","w",stdout); 27 28 int k,n,m; 29 scanf("%d%d%d",&k,&n,&m); 30 for(int i=1;i<=k;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c); 31 sort(a+1,a+k+1); 32 int w=1,ans=0; 33 queue <int> q; 34 for(int i=1;i<=n;i++) 35 { 36 if(!q.empty()) 37 { 38 while(q.front()==i) {q.pop();ans++;} 39 } 40 while(a[w].x<i) w++; 41 while(a[w].x==i && q.size()<m) 42 { 43 for(int j=1;j<=a[w].c;j++) 44 if(q.size()<m) q.push(a[w].y); 45 else break; 46 w++; 47 } 48 49 } 50 printf("%d",ans); 51 return 0; 52 }b
非線段樹AC思路:
首先我們知道一個經典問題:有n個區間,找盡可能多的區間使得區間之間不相交。
這道題的做法就是按右端點從小到大排序,然後找其中的不相交區間就好了。
第二題可以說是這道題的一個變形。易證如果不取任意可取的線段,則會浪費一段空間。(說白了就是一個貪心。拿到60分)
100分:維護貪心。維護一個f[i]表示i這個時刻,車上已經坐了幾只怪獸。
因為是老師臨時想出來的,沒有標程。
下面是線段樹做法。裏面應該是有線段樹的模板的,可以借這道題背下來。
1 //線段樹模板! 2 #include <cmath> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 int tree[65536][4],n,m,c,i,MIN,ans; 9 struct node 10 { 11 int x; 12 int y; 13 int z; 14 }; 15 node A[100005]; 16 int cmp(node i,node j) 17 { 18 return i.y<j.y; 19 } 20 void Update(int k) 21 { 22 tree[k*2][2]+=tree[k][3]; 23 tree[k*2+1][2]+=tree[k][3]; 24 tree[k*2][3]+=tree[k][3]; 25 tree[k*2+1][3]+=tree[k][3]; 26 tree[k][3]=0; 27 } 28 void work(int root,int l,int r,int k) 29 { 30 if (l==tree[root][0] && r==tree[root][1]) 31 { 32 tree[root][2]+=k; 33 tree[root][3]+=k; 34 return; 35 } 36 Update(root); 37 int mid=(tree[root][0]+tree[root][1])/2; 38 if (l<=mid) work(root*2,l,min(mid,r),k); 39 if (r>mid) work(root*2+1,max(mid+1,l),r,k); 40 tree[root][2]=min(tree[root*2][2],tree[root*2+1][2]); 41 } 42 int find(int root,int l,int r) 43 { 44 if (l==tree[root][0] && r==tree[root][1]) return tree[root][2]; 45 Update(root); 46 int mid=(tree[root][0]+tree[root][1])/2,p=453266144,q=453266144; 47 if (l<=mid) p=find(root*2,l,min(mid,r)); 48 if (r>mid) q=find(root*2+1,max(mid+1,l),r); 49 return min(p,q); 50 } 51 int main() 52 { 53 freopen("bus.in","r",stdin); 54 freopen("bus.out","w",stdout); 55 scanf("%d%d%d",&n,&m,&c); 56 for (i=32768; i<=65535; i++) tree[i][0]=tree[i][1]=i; 57 for (i=32767; i>=1; i--) 58 { 59 tree[i][0]=tree[i*2][0]; 60 tree[i][1]=tree[i*2+1][1]; 61 } 62 work(1,1+32767,m+32767,c); 63 for (i=1; i<=n; i++) 64 { 65 scanf("%d%d%d",&A[i].x,&A[i].y,&A[i].z); 66 A[i].y--; 67 } 68 sort(A+1,A+n+1,cmp); 69 for (i=1; i<=n; i++) 70 { 71 MIN=find(1,A[i].x+32767,A[i].y+32767); 72 if (MIN>A[i].z) 73 { 74 work(1,A[i].x+32767,A[i].y+32767,-A[i].z); 75 ans+=A[i].z; 76 } 77 else 78 { 79 work(1,A[i].x+32767,A[i].y+32767,-MIN); 80 ans+=MIN; 81 } 82 } 83 cout<<ans; 84 return 0; 85 }bstd
今日專題是dp。然而筆記全記在word裏了。然後word保存在郵箱裏了。這裏就不再寫了、
清北學堂Day3