HIT2020暑期集训 二分三分,java大数与stl
Day1
(本不该出现在这的题)注释瞎写了一下,因为各种原因WA了很久。。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 1000005 using namespace std; typedef long long ll; int first[maxn],last[maxn],pre[maxn][2],a[maxn]; ll ans; int main() { int i,n,x; int l,r; scanf("%d%d",&n,&x); for (i=0;i<=x+1;i++) { first[i]=n+1; last[i]=0; } for (i=1;i<=n;i++) { scanf("%d",&a[i]); first[a[i]]=min(first[a[i]],i); last[a[i]]=max(last[a[i]],i); } pre[x][0]=first[x]; pre[x+1][0]=n+1; pre[1][1]=last[1]; for (i=x-1;i>=1;i--) pre[i][0]=min(first[i],pre[i+1][0]);//后面的数中出现在最前面的 for (i=2;i<=x;i++) pre[i][1]=max(last[i],pre[i-1][1]);//前面的数中出现在最后面的 for (i=x;i>=2 && last[i-1]<=pre[i][0];i--); //保证当前的数出现的最后位置 在其后面所有数出现的最前位置 之前 r=i-1;ans=0; for (l=1;l<=x;l++) { while ((pre[r+1][0]<pre[l-1][1] && r<=x) || r<l) r++;//使区间l,l前的最后位 在 r后的最前位 之前 ans+=1ll*(x-r+1); if (l!=1 && first[l]<pre[l-1][1]) break;//若l前的最后位 在l出现的最前位 之后,退出 } printf("%lld\n",ans); return 0; }
G题 POJ 1131
JAVA BigDecimal函数的使用 八进制小数转十进制小数(白学Java课了,搞半天搞不出来)
import java.util.*; import java.io.*; import java.math.BigDecimal; public class Main { public static void main(String[] args) throws IOException { Scanner cin=new Scanner(new BufferedInputStream(System.in)); BigDecimal x=new BigDecimal(1); BigDecimal y=new BigDecimal(8); String n=null; while(cin.hasNext()) { BigDecimal ans=new BigDecimal(0); BigDecimal bit=x.divide(y); n=cin.next(); for(int i=2;i<n.length();++i) { ans=ans.add(bit.multiply(new BigDecimal(n.charAt(i)-'0'))); bit=bit.divide(y); } System.out.println(n+" [8] = "+ans.toString()+" [10]"); } } }
Day2
B题 HDU 4122
C题 计蒜客 - A1761
花里胡哨的题面成功迷惑了我。。。
其实就是实现一个能够push,pop,查找最大值的栈。
考虑到栈为后进先出,push一个比当前栈中最大值小的数没有意义。于是每次比较当前数和当前最大值,push新的最大值即可(就是 push(max(x,maximum)) )这样就可以保证栈顶是当前栈中的最大值了。
然后记得开long long(为啥又忘记开了)
#include<cstdio> int n,p,q,m,add,top; long long stk[5000005],ans; unsigned int SA,SB,SC; unsigned int rng61() { SA^=SA<<16; SA^=SA>>5; SA^=SA<<1; unsigned int t=SA; SA=SB; SB=SC; SC^=t^SA; return SC; } void gen() { scanf("%d%d%d%d%u%u%u",&n,&p,&q,&m,&SA,&SB,&SC); for(int i=1;i<=n;i++) { if (rng61()%(p+q)<p) { add=rng61()%m+1; if (top!=0 && stk[top]>add) add=stk[top]; stk[++top]=add; } else if (top>0) top--; if (top!=0) ans^=i*stk[top]; } } int main() { int i,t; scanf("%d",&t); for (i=1;i<=t;i++) { top=0;ans=0; gen(); printf("Case #%d: %lld\n",i,ans); } return 0; }
F题 HDU 1506
给出N个下端对齐、连续排列的矩形的高(它们的宽度都为1),求最大矩形面积(我这题目描述没救了,看原题面吧。。。。。)
可知,对于每个矩形找到两侧连续且比他高的矩形数,将矩形高度乘以矩形数就能得到面积,在N个面积中最大的就是答案。
求这个矩形数,只要找到两侧从当前矩形开始,第一个比该矩形矮的矩形序号就可以了。
所以从左往右,从右往左分别维护一个单调栈。当当前高度大于栈顶高度时将其压入栈;当当前高度小于等于栈顶高度时就不断弹出直至当前高度大于栈顶高度,此时栈顶元素就是第一个比当前矩形矮的矩形。
最后,ans记得开long long(我哭了)
#include<cstdio> #define maxn 100005 int l[maxn],r[maxn],h[maxn],stk[maxn],n,top; int main() { int i,top; long long now,ans; while (scanf("%d",&n)!=EOF && n!=0) { for (i=1;i<=n;i++) scanf("%d",&h[i]); top=0; for (i=1;i<=n;i++) { while (top && h[i]<=h[stk[top]]) top--;//把比当前元素大的都弹出 if (!top) l[i]=0; else l[i]=stk[top];//左边最靠近当前元素且比当前元素小的 stk[++top]=i; } top=0; for (i=n;i>=1;i--) { while (top && h[i]<=h[stk[top]]) top--; if (!top) r[i]=n+1;//同理,右边 else r[i]=stk[top]; stk[++top]=i; } ans=0; for (i=1;i<=n;i++) { now=(long long)(r[i]-l[i]-1)*h[i]; if (now>ans) ans=now; } printf("%lld\n",ans); } return 0; }
大概就是,给一个长度为N的序列,求其中每个元素与位于它右边、比它小、且位置最右边的元素的距离。
具体做法是,从右至左,维护一个单调递减的栈(即当元素比栈顶元素小时将其入栈),每当当前元素比栈顶元素大的时候,在栈中找到比当前元素小且最大的元素(这个过程可以用lower_bound函数或者二分查找),就可以求出答案了。
lower_bound (没想到lower_bound还可以这么用。。涨知识了)
#include<cstdio> #include<algorithm> using namespace std; #define maxn 100005 int a[maxn],ans[maxn],stk[maxn],num[maxn],top; bool cmp(int x,int y){return x>y;} int main() { int i,n,it,ma=0; scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%d",&a[i]); if (a[i]>ma) ma=a[i]; } stk[0]=ma+1; for (i=n;i>=1;i--) { if (stk[top]>a[i]) { stk[++top]=a[i]; num[top]=i;ans[i]=-1; } else if (stk[top]==a[i]) ans[i]=-1; else if (stk[top]<a[i]) { it=lower_bound(stk+1,stk+top+1,a[i],cmp)-stk; if (a[i]==stk[it]) it++; ans[i]=num[it]-i-1; } } for (i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }
二分版本(部分)
else if (stk[top]<a[i]) { l=1;r=top; while (l<=r) { mid=(l+r)>>1; if (stk[mid]>=a[i]) l=mid+1; else r=mid-1; } ans[i]=num[l]-i-1; }