codeforces699 div2 ABC | cf699 div2 abc | 貪心,貪心,還是貪心
今日的cf題解,與總結,又因為本地的程式總被刪掉,所以把除錯過程也加上,作為日後回顧。
無趣的刷題才是日常,本文遵循的方法論在這篇文章中。https://www.cnblogs.com/cosmowind/p/15982590.html
A
1、概括題面:在座標軸上,機器人初始位置為(0,0),輸入一串指令UDLR,分別表示上下左右走一格。問,每個指令可以接受或執行,機器人能否走到(x,y)?
2、分析過程:
①關鍵詞:貪心
②思路:只走能接近目標的指令,其餘忽略。
③實現:統計各個指令的個數,最後判斷需要的方向上的指令數是否能達到目標。
④複雜度:o(n)
3、貼個程式碼:
#include<iostream> #include<stdio.h> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<map> #include<vector> using namespace std; #define _for(i,a,b) for(int i=(a);i<=(b);i++) #define _rp(i,b,a) for(int i=(b);i>=(a);i--) //#define int long long #defineclose std::ios::sync_with_stdio(0) typedef long long ll; const int N=2e5+7; int t,a,b; string s; signed main(){ cin>>t; while(t--){ cin>>a>>b; cin>>s; _for(i,0,s.length()-1){ if(a>0){ if(s[i]=='R')a--; }else if(a<0){ if(s[i]=='L')a++; } if(b>0){ if(s[i]=='U')b--; }else if(b<0){ if(s[i]=='D')b++; } } if(!a&&!b)cout<<"YES\n";else cout<<"NO\n"; } }
B(如果不是因為寫部落格,這題我再也不想看)
1、概括題面:n座山,分別有高度a[i]。給定k顆滾石,每顆滾石從第一座山開始向右滾,如果下一座山不高於自己,就滾到下一座山,最後滾到世界盡頭;否則留在這座山,使之高度+1。問,第k顆滾石會停在哪?
2、分析過程:
①關鍵詞:貪心、分類討論
②思路:根據題意,在遇到一座高山時,需要把它之前的所有矮山都填到與自己同高才能通過。所以維護一個單調棧,每遇到一座比當前高的山,就把棧內所有比它低的山都拿出來填,如果k用完了,說明最後的滾石就在當前的高山以前(不包括它),棧內最頂部的元素之後(包括它),具體演算法是用left_k對兩者距離取模,具體實現見程式碼。如果遍歷完所有山k>0,則輸出-1。
③重要細節:當對棧裡的最小元素進行填山時,應該注意到不能直接把這座山填到和高山一樣的高度,因為,如果當棧內最小元素達到次小元素的大小時,同時填山的區間就會擴大,此時將最小元素退棧,用次小元素繼續執行。
④複雜度:o(n)
3、貼個程式碼:
#include<iostream> #include<stdio.h> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<map> #include<vector> using namespace std; #define _for(i,a,b) for(int i=(a);i<=(b);i++) #define _rp(i,b,a) for(int i=(b);i>=(a);i--) //#define int long long #define close std::ios::sync_with_stdio(0) typedef long long ll; const int N=2e5+7; int t,a[N],b,s[N],bord,n,k,flag,ans,calc; vector<int> zh; signed main(){ cin>>t; while(t--){ cin>>n>>k; s[0]=0; a[0]=N; _for(i,1,n)cin>>a[i],s[i]=s[i-1]+a[i]; zh.clear(); zh.push_back(0); zh.push_back(1); flag=0;ans=-1; _for(i,2,n){ while(zh.size()>0&&a[zh.back()]<a[i]){ bord=zh.back(); if(zh.size()>1&&a[zh.back()-1]<a[i]){ calc=((i-bord)*a[zh.back()-1])-(s[i-1]-s[bord-1]); if(calc<k){ k-=calc; _for(j,bord,i-1)a[j]=a[zh.back()-1]; _for(j,1,n)s[j]=s[j-1]+a[j]; //cout<<k<<" "<<bord<<" "<<a[2]<<endl; }else{ //cout<<"there\n"; ans=i-1-(k-1)%(i-bord); //cout<<bord<<" "<<i<<" "<<a[bord]<<" "<<a[i]<<" "<<calc<<" "<<ans<<endl; flag=1; break; } zh.pop_back(); }else{ calc=((i-bord)*a[i])-(s[i-1]-s[bord-1]); //cout<<bord<<" "<<i<<" "<<a[bord]<<" "<<a[i]<<" "<<calc<<" "<<ans<<endl; if(calc<k){ k-=calc; _for(j,bord,i-1)a[j]=a[i]; _for(j,1,n)s[j]=s[j-1]+a[j]; //cout<<k<<" "<<bord<<" "<<a[2]<<endl; }else{ //cout<<"there\n"; ans=i-1-(k-1)%(i-bord); //cout<<bord<<" "<<i<<" "<<a[bord]<<" "<<a[i]<<" "<<calc<<" "<<ans<<endl; flag=1; break; } } } if(a[i]<a[zh.back()])zh.push_back(i); //zh.push_back(i); if(flag)break; /* cout<<"look "<<zh.size()<<" "<<zh.back()<<endl; _for(j,0,zh.size()-1)cout<<zh[j]<<" ";cout<<endl; _for(j,0,zh.size()-1)cout<<a[zh[j]]<<" ";cout<<endl; */ } if(flag)cout<<ans<<endl;else cout<<-1<<endl; } } /* 1 12 172 60 7 60 49 5 80 1 78 41 9 57 65 25 2114 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 */
C
1、概括題面:n個柵欄,原有顏色a[i],目標顏色b[i],先後請來m個粉刷匠,只能給1個柵欄上色為c[i]。問,能否達到目標?粉刷匠分別給哪個柵欄上色?
2、分析過程:產生做法的思路過程,總體說解題演算法的關鍵詞,某某資料結構,dp狀態之類的。對一些重要的細節,討論的過程進行具體闡述。最後分析複雜度。
①關鍵詞:貪心(除了貪心不知道怎麼描述)
②思路:首先倒著列舉粉刷匠,因為越靠後的粉刷匠越不會被其它顏色遮蓋。對於每個粉刷匠,做三個判斷:(1)對應的顏色還有沒有需要塗的?qu[c[i]]>0?【進行上色任務】(2)目標顏色b[i]中是否有c[i]這個顏色?【無需該色,找個不做負面影響的地方】(3)該粉刷匠是否為倒數第一個粉刷匠?如果是最後的粉刷匠,又沒有對目標做貢獻,也沒有相同顏色存放自己,那就只能破壞計劃,直接輸出 NO。
③重要細節:為執行以上功能,我們需要預處理出相應的陣列。qu[i]表示顏色i需要用在第qu[i]個柵欄上;last[i]表示與位置i上顏色相同且也需要上色的上一個位置在哪,若沒有則為0;
④複雜度:o(n)
3、貼個程式碼:程式碼中還有其它的優化,實際上不要也罷。比如,統計粉刷匠能提供的顏色數以及某種顏色需要的個數,若前者較小,則失敗。
#include<iostream> #include<stdio.h> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<map> #include<vector> using namespace std; #define _for(i,a,b) for(int i=(a);i<=(b);i++) #define _rp(i,b,a) for(int i=(b);i>=(a);i--) //#define int long long #define close std::ios::sync_with_stdio(0) #define mst(f,a) memset(f,a,sizeof(f)); #define die cout<<"NO\n";return typedef long long ll; const int N=1e5+7; int n,m,t,a[N],b[N],c[N],qu[N],last[N],cnt_lai[N],cnt_que[N],wri[N],po[N]; string s; void solve(){ cin>>n>>m; mst(last,0); mst(qu,0); mst(cnt_lai,0); mst(cnt_que,0); mst(wri,0); mst(po,0); _for(i,1,n)cin>>a[i]; _for(i,1,n)cin>>b[i]; _for(i,1,m)cin>>c[i],cnt_lai[c[i]]++; _for(i,1,n){ if(a[i]!=b[i]){ cnt_que[b[i]]++; //if(qu[b[i]]){ last[i]=qu[b[i]]; qu[b[i]]=i; //cout<<b[i]<<" "<<a[i]<<" "<<i<<" "<<qu[b[i]]<<endl; //} if(cnt_lai[b[i]]<cnt_que[b[i]]){ die; } } po[b[i]]=i; } //cout<<"there\n"; _rp(i,m,1){ //cout<<" "<<i<<" "<<t<<endl; if(qu[c[i]]>0){ wri[i]=qu[c[i]]; qu[c[i]]=last[qu[c[i]]]; //cout<<"__ "<<i<<" "<<t<<" "<<wri[i]<<" "<<qu[c[i]]<<endl; }else if(po[c[i]]>0){ wri[i]=po[c[i]]; //cout<<"++ "<<i<<" "<<t<<endl; }else if(i<m){ wri[i]=wri[m]; //cout<<"33 "<<i<<" "<<t<<endl; }else{ die; } } _for(i,1,n){ if(qu[i]){ die; } } cout<<"YES\n"; _for(i,1,m){ cout<<wri[i]<<" "; a[wri[i]]=c[i]; } cout<<endl;/* _for(i,1,n){ cout<<a[i]<<" "; } cout<<endl; */ } signed main(){ close; cin>>t; while(t--){ solve(); } } /* 1 27 24 21 18 18 23 17 8 7 21 12 10 3 13 5 16 3 17 7 27 20 18 2 5 3 26 22 24 2 15 9 18 23 17 8 7 21 12 10 3 13 5 16 3 17 13 27 22 18 2 5 3 25 22 24 2 22 9 27 15 7 20 7 9 6 27 11 1 11 23 12 25 19 22 9 15 11 13 5 9 */