應該一眼看出來是貪心題,然后想最優解是什么。正確的貪心策略是【原棋盤上每個位置的棋子】都往最近的左邊【目標棋盤上棋子】移動,如果左邊沒有棋子了那就閑置最后處理,如果目標棋盤在該位置上也有棋子,那就算距離為0(最近)。最后處理的話,棋盤上的局面應該是所有的棋子都得往右移,這樣的話怎么移都無所謂了,樸素的把放過去。
模擬的時候難度在于通過upper bound找到離該位置最近左的位置,所以復雜度是O(NlogN);如果樸素的遍歷數組找最近左需要N復雜度,整體n^2就過不了了。
?
?對于upper_bound來說,返回的是被查序列中第一個大于查找值的指針,也就是返回指向被查值>查找值的最小指針,lower_bound則是返回的是被查序列中第一個大于等于查找值的指針,也就是返回指向被查值>=查找值的最小指針。 【引用自 https://blog.csdn.net/u011008379/article/details/50725670 】
?
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上,但自己編了幾個數據都過了。