C. Balanced Stone Heaps
题意:给n堆石头,对于第 [3,n] 堆石头,每次选择一个任意的数d,给第 i-1 堆石头加d/3个,i-2 堆石头加d/3*2个,求最后所有石头堆最小数目的最大值。
解:二分嘛。一开始想的直接倒着来一遍,发现没过样例。一想每堆石头只能由后面两堆补足,不能继承再后面的石头。因此把继承的和本来有的分开算,还是倒着来。如果能够继承到足够多的石头,就全部分给前面;如果加上继承的才够,那就把多的那部分分出去;如果加上都不够,那直接return 0 吧。
T了好几次。慎用memset啊慎用memset。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define eps 0.00000001 #define inf 0x7fffffff //#define int long long int n; int a[maxx],t[maxx]; int check(int x){ for(int i=1;i<=n;i++) t[i]=0; for(int i=n;i>=3;i--){ if(a[i]+t[i]>=x){ if(t[i]>=x){ t[i-1]+=a[i]/3; t[i-2]+=a[i]/3*2; }else{ int temp=a[i]+t[i]-x; t[i-1]+=temp/3; t[i-2]+=temp/3*2; } } else return 0; } if(a[1]+t[1]<x||a[2]+t[2]<x) return 0; return 1; } signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n); int maxn=0; for(int i=1;i<=n;i++) { scanf("%d", &a[i]); maxn=max(maxn,a[i]); } int l=0,r=maxn,mid; int ans; while(l<=r){ mid=l+(r-l)/2; if(check(mid)){ ans=mid; l=mid+1; } else r=mid-1; } printf("%d\n",ans); } return 0; }
d题算期望,实不相瞒我到现在都不会算期望qaq
**E. Middle Duplication
题意:给出一棵树,每个结点上有个字母,以中序遍历这棵树会得到一个字符串。现在可以重复其中不多于k个字母,但重复的字母的父亲节点也要重复,都算在k里面。问能构成的字典序最小的字符串是什么。
解:树上的问题先拍平了看。有一个字符串,选k个重复,要求字典序最小。那必然从前往后,找到满足类似 s[i]<s[i+1] 的字母重复。如果有一串相等,那就找出第一个与之不相等的比较。
现在把它放回树上。左子树在当前结点前面,右子树在当前节点后面。先不考虑k的限制,如果左孩子比现在小,那我一定选它;如果右孩子比现在大,那我会选当前结点。显然越靠左越好。现在加回k。如果我选了深度为x的结点,那这一路上我还要选它所有的祖先,共x个点。x≤k 即可。
还有卡了半天的是左子树能选就选,右子树中会有点局部满足要求,但选了会导致较大祖先结点重复,最终字典序变大。因此右子树只在当前节点选择后才考虑。其实最后就是几行代码顺序的区别XD
写的时候参考了别人的代码,用树剖记录top的方式计算这条链上共有几个点。很好看。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define eps 0.00000001 #define inf 0x7fffffff //#define int long long int n,k; char s[maxx]; int tr[maxx][2],depth[maxx]; int vis[maxx]={0},rvis[maxx]={0}; vector<int> a; void dfs1(int now,int d){ depth[now]=d+1; if(tr[now][0]) dfs1(tr[now][0],d+1); a.push_back(now); if(tr[now][1]) dfs1(tr[now][1],d+1); } int dfs2(int now,int top){ int flag=0; if(tr[now][0]) flag=dfs2(tr[now][0],top); if(flag) rvis[now]=1; if(!flag&&vis[now]){ int temp=depth[now]-depth[top]+1; if(k>=temp){ rvis[now]=1; k-=temp; flag=1; } else flag=0; } if(tr[now][1]&&flag) dfs2(tr[now][1],tr[now][1]); return flag; } signed main() { scanf("%d%d",&n,&k); scanf("%s",s+1); for(int i=1;i<=n;i++) scanf("%d%d",&tr[i][0],&tr[i][1]); dfs1(1,1); int idx=n-1; for(int i=n-1;i>=0;i--){ if(s[a[i]]<s[a[idx]]) vis[a[i]]=1; if(i!=0) if(s[a[i]]!=s[a[i-1]]) idx=i; } dfs2(1,1); for(int i=0;i<a.size();i++){ printf("%c",s[a[i]]); if(rvis[a[i]]) printf("%c",s[a[i]]); } printf("\n"); return 0; }