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 #define close 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 */