【Codeforces #134 Div2】Solutions 【Updated】
ID飘紫了,进Div1.
【A Mountain Scenery】
http://www.codeforces.com/contest/218/problem/A
题目大意:有n个山峰,主人公会选k个山峰并把他增高一单位。现在给你修改之后的让还原。
随便找k个山头,只要符合条件就削矮一单位就可以了。注意关于初始山峰的定义,y[i]>y[i-1]且y[i]>y[i+1],一定要大于。
#include <iostream> using namespace std; int a[1000],n,k; int main(){ cin>>n>>k; for(int i=1;i<=2*n+1;i++){ cin>>a[i]; } while(k--){ for(int i=1;i<=2*n+1;i++) if(!(i&1)){ if(a[i]-a[i-1]>1 && a[i]-a[i+1]>1){ a[i]--; break; } } } for(int i=1;i<2*n+1;i++) cout<<a[i]<<" "; cout<<a[2*n+1]<<endl; }
【B Airport】
http://www.codeforces.com/contest/218/problem/B
题目大意:有n个旅客,m架飞机,每个飞机容量a[i]。旅客任意选择飞机, 票价为机上当前空座数量。问机场最大最小收益是多少。
由于n,m很小,可以弄一个数组每次找最小(大)的就可以了。
鉴于编程复杂度,写个堆更简单。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <utility> #define MP make_pair #define dis first #define pos second using namespace std; typedef pair<int,int> PII; template<class T>inline void gmax(T &a,T b){if(a<b)a=b;} template<class T>inline void gmin(T &a,T b){if(a>b)a=b;} priority_queue< int,vector<int>,less<int> > heap; priority_queue< int,vector<int>,greater<int> > mheap; int n,m,x,ans; int main(){ cin>>n>>m; for(int i=1;i<=m;i++){ cin>>x; heap.push(x); mheap.push(x); } for(int i=1;i<=n;i++){ x=heap.top();heap.pop(); ans+=x; x--; heap.push(x); } cout<<ans<<" "; ans=0; while(n--){ x=mheap.top();mheap.pop(); ans+=x; x--; if(x) mheap.push(x); } cout<<ans<<endl; }
【C Ice Skating】
http://www.codeforces.com/contest/218/problem/C
题目大意:滑雪场上n个雪堆,每个能与上下左右四个方向所有雪堆相联系。问最少添加几个雪堆,使得任意两个雪堆直接或间接相联系。
求出所有雪堆组成的联通块个数,答案就是联通块个数-1.
这题两种方法:1.dfs每个联通块。2.用并查集维护。
简要说一下并查集维护的方法:每一行、每一列都抽象为一个点,假设(x,y)上有一个雪堆,那么第x行上的所有雪堆和第y列上的所有雪堆一定都属于一个联通块,于是我们可以把x和y所代表的集合合并。
此题数据范围不大,要是大一些的话只能并查集了。
#include <iostream> using namespace std; int n,m,p,x,y,fa[2000010],ans; bool vis[2000010]; int find(int x){ if(x==fa[x]) return x; else return fa[x]=find(fa[x]); } int main(){ cin>>n; for(int i=1;i<=2000;i++) fa[i]=i; for(int i=1;i<=n;i++){ cin>>x>>y; fa[find(1000+y)]=find(x); vis[x]=true; } for(int i=1;i<=1000;i++) if(vis[i] && fa[i]==i) ans++; cout<<ans-1<<endl; }
【D Blackboard Fibonacci】
http://www.codeforces.com/contest/218/problem/D
题目大意:初始一个二元组(0,1)。对于某一个二元组有两种操作:
T操作(x,y)→(x+y,y)
B操作(x,y)→(x,x+y)
给定n和r,问是否能恰好n次操作使的最后一个修改的数字为r,且使得操作序列相邻操作相同的次数最少,并给出操作序列。
比赛的时候由于想错了时间复杂度导致这个题我没敢写,灰常可惜……毕竟这种赛制搞不好要掉Rating的,所以也没办法……
不管是T操作还是B操作,最后一个修改的数一定是大于原来的两个数的,比如 T(x,y)→T(x+y,y),x+y>x,x+y>y,这是显然的。
那么我们可以逆向思维,由一个末状态推初状态。假设当前状态为(x,y),且x≥y,那么之前一个状态一定是(x-y,y);x<y类似。枚举到最初状态之后检查一下操作序列就可以了。
枚举末状态这一步是O(r)的,对于每一个状态向前推,因为中间数字都是斐波那契数列中的数字,增长速度是很快的,复杂度并不大,所以总复杂度满足要求。
↑我把O(r)想成了O(r^2),忘了状态里的两个数有一个是确定的了= =!
为了抢全场最短稍微压了一下……
#include <iostream> #define INF ~0u>>1 #define mn 1000010 using namespace std; char move[mn],res[mn]; int ans=INF,n,r,cur; void check(int x,int y){ for(cur=n-1;x*y!=0 && cur>=0;cur--) if(x>=y) x-=y,move[cur]='T'; else y-=x,move[cur]='B'; if(cur!=-1 || !(x==0 && y==1)) return; int tmp=0; for(int i=1;i<n;i++) if(move[i]==move[i-1]) tmp++; if(tmp<ans){ ans=tmp; for(int i=0;i<n;i++) res[i]=move[i]; } } int main(){ cin>>n>>r; for(int i=0;i<=r;i++) check(i,r),check(r,i); if(ans==INF) cout<<"IMPOSSIBLE"<<endl; else cout<<ans<<endl<<res<<endl; }
【E Formurosa】【UPD】
http://www.codeforces.com/contest/218/problem/E
在题解之前搞出来了……
题目大意:有N个细菌,每个细菌为0或1,所有细菌不会全部相同。给出一个位运算的表达式,问通过适当方法把细菌代号填进去,能否确定每种细菌的种类。
围观了若干大神的代码无果,果断提问了,如下是一个不错的答复:(不要吐槽我的英语……)
第二个问题问的太2了……秀下限了……
意思大概就是对于一个表达式任意填两个数看能否推断出他们的种类。
#include <iostream> #include <cstring> using namespace std; int n,match[1000010],Stack[1000010],tot; bool f[1000010][2][2]; char s[1000010]; int main(){ cin>>n>>s; n=strlen(s); for(int i=0;i<n;i++) if(s[i]=='(') Stack[++tot]=i; else if(s[i]==')'){ match[i]=Stack[tot]; match[Stack[tot--]]=i; } for(int i=0;i<n;i++){ switch(s[i]){ case '0':f[i][0][0]=1; break; case '1':f[i][1][1]=1; break; case '?':f[i][0][1]=f[i][1][0]=1; break; case ')':int P_oper=s[i-1]==')'?(match[i-1]-1):(i-2); char oper=s[P_oper]; int P_left=P_oper-1; int P_right=i-1; for(int p=0;p<2;p++) for(int q=0;q<2;q++) if(f[P_left][p][q]) for(int x=0;x<2;x++) for(int y=0;y<2;y++) if(f[P_right][x][y]){ switch(oper){ case '&':f[i][p&x][q&y]=1; break; case '|':f[i][p|x][q|y]=1; break; case '^':f[i][p^x][q^y]=1; } } } } if(f[n-1][0][1] ||f[n-1][1][0])cout<<"YES"<<endl; else cout<<"NO"<<endl; return 0; }