2018美團CodeM編程大賽 Round A Problem 2 下棋 【貪心】
阿新 • • 發佈:2018-06-10
AC 什麽 vector col break begin 遍歷 boa 需要
應該一眼看出來是貪心題,然後想最優解是什麽。正確的貪心策略是【原棋盤上每個位置的棋子】都往最近的左邊【目標棋盤上棋子】移動,如果左邊沒有棋子了那就閑置最後處理,如果目標棋盤在該位置上也有棋子,那就算距離為0(最近)。最後處理的話,棋盤上的局面應該是所有的棋子都得往右移,這樣的話怎麽移都無所謂了,樸素的把放過去。
模擬的時候難度在於通過upper bound找到離該位置最近左的位置,所以復雜度是O(NlogN);如果樸素的遍歷數組找最近左需要N復雜度,整體n^2就過不了了。
1 #include<iostream> 2 #include<algorithm> 3#include<map> 4 #include<vector> 5 using namespace std; 6 7 int board[100005]; 8 vector<int> va; 9 map<int,int> m; 10 long long ans; 11 //貪心策略 12 //每個都向自己最近的左邊的棋子移動 13 int main(){ 14 int n; cin>>n; 15 for(int i=1;i<=n;i++) cin>>board[i]; 16 for(int i=1;i<=n;i++){ 17 int x; cin>>x; 18 if(x){//這個位置上有棋子 19 va.push_back(i); 20 m[i]=x; 21 } 22 } 23 24 for(int i=1;i<=n;i++){ 25 while(1){ 26 vector<int>::iterator index = upper_bound(va.begin(),va.end(),i);/* index指向第一個大於i的元素*/ 27 //如果沒有比i還大的,返回begin() 28 if(index==va.begin()) break;//目標盤左邊沒有棋子了 29 index--; 30 if( m[ *index ]>board[i] ) { 31 ans+=(i-(*index) )*board[i]; 32 m[*index]-=board[i]; 33 board[i]=0; 34 break; 35 } 36 if( m[ *index ]==board[i] ){ 37 ans+=(i-(*index))*board[i]; 38 va.erase(index); 39 board[i]=0; 40 break; 41 } 42 if( m[ *index]<board[i]){ 43 ans+=(i-(*index))*m[ *index]; 44 va.erase(index); 45 board[i]-=m[*index]; 46 } 47 } 48 } 49 50 for(int i=1;i<=n;i++){ 51 if(board[i]==0) continue; 52 while(1){ 53 if( m[ va[0] ]>board[i] ) { 54 ans+=(i+va[0]-2)*board[i]; 55 m[ va[0] ]-=board[i]; 56 break; 57 } 58 if( m[ va[0] ]== board[i] ){ 59 ans+=(i+va[0]-2)*board[i]; 60 va.erase(va.begin()); 61 break; 62 } 63 if( m[ va[0] ]<board[i]){ 64 ans+=(i+va[0]-2)*m[ va[0] ]; 65 va.erase(va.begin()); 66 board[i]-=m[ va[0] ]; 67 } 68 } 69 } 70 71 cout<<ans<<endl; 72 73 return 0; 74 }
沒有提交在美團的oj上,但自己編了幾個數據都過了。
2018美團CodeM編程大賽 Round A Problem 2 下棋 【貪心】