A
\(map\)应用
#include<bits/stdc++.h> using namespace std; namespace red{ #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define mid ((l+r)>>1) inline int read() { int x=0;char ch,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-')f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } string s; int sum,ret; inline void main() { while(getline(cin,s)) { if(s[0]=='+') ++sum; else if(s[0]=='-') --sum; else { int t=s.find(':'); ret+=sum*(s.size()-1-t); } } cout<<ret; } } signed main() { red::main(); return 0; }
B
找到最长的一串,然后模拟就好了
#include<bits/stdc++.h> using namespace std; namespace red{ #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define mid ((l+r)>>1) inline int read() { int x=0;char ch,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-')f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } string s[1010]; int maxn,opt=1,len[1010]; inline void main() { int i=1; while(getline(cin,s[i])) { len[i]=s[i].size(); maxn=max(maxn,len[i]); ++i; } --i; for(int j=1;j<=maxn+2;++j) putchar('*'); putchar('\n'); for(int j=1;j<=i;++j) { putchar('*'); if((maxn&1)!=(len[j]&1)) { opt=-opt; for(int k=1;k<=(maxn-len[j]+opt)>>1;++k) putchar(' '); cout<<s[j]; for(int k=1;k<=(maxn-len[j]-opt)>>1;++k) putchar(' '); } else { for(int k=1;k<=(maxn-len[j])>>1;++k) putchar(' '); cout<<s[j]; for(int k=1;k<=(maxn-len[j])>>1;++k) putchar(' '); } puts("*"); } for(int j=1;j<=maxn+2;++j) putchar('*'); } } signed main() { red::main(); return 0; }
C
好题
把左括号看作\(+1\),右括号看作\(-1\),考虑一个合法子段满足的要求:子段和为\(0\),且不存在一个地方前缀和小于\(0\)
考虑维护一个\(vector\),里面每个前缀和出现的位置,相同前缀和之间的子段和一定为\(0\)
维护然后对于每个子段用个数据结构维护一下中间的前缀和最小值,如果是满足要求的子段,那么前缀和最小值应该小于与右端点
这个过程我们发现可以二分
然后\(TLE\)了……
然后发现其实用指针不停地往右走就行了
#include<bits/stdc++.h> using namespace std; namespace red{ #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define mid ((l+r)>>1) inline int read() { int x=0;char ch,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-')f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1e6+10; char s[N]; int n,sum=1e6; int ret,num=1; int tp[N<<1]; vector<int> q[N<<1]; int ans[N<<2]; inline void update(int pos,int l,int r,int p,int k) { if(l==r) { ans[p]=k; return; } if(pos<=mid) update(pos,l,mid,ls(p),k); else update(pos,mid+1,r,rs(p),k); ans[p]=min(ans[ls(p)],ans[rs(p)]); } inline int query(int tl,int tr,int l,int r,int p) { if(tl<=l&&r<=tr) return ans[p]; int ret=1e9+7; if(tl<=mid) ret=min(ret,query(tl,tr,l,mid,ls(p))); if(tr>mid) ret=min(ret,query(tl,tr,mid+1,r,rs(p))); return ret; } inline void main() { scanf("%s",s+2); n=strlen(s+2)+1; q[sum].push_back(1); update(1,1,n,1,sum); for(int i=2;i<=n;++i) { if(s[i]=='(') ++sum; else --sum; update(i,1,n,1,sum); q[sum].push_back(i); while(query(q[sum][tp[sum]],i,1,n,1)<sum) ++tp[sum]; int now=q[sum][tp[sum]]; if(i-now==ret) ++num; if(i-now>ret) ret=i-now,num=1; } if(!ret) num=1; printf("%d %d\n",ret,num); } } signed main() { red::main(); return 0; }
D
纯高中物理题……也就是俗说的假伯题
懒得自己推了直接颓了题解
题解的\(code\)好精简啊
设\(f(v_0,v,a,l)\)表示初速度为\(v0\),速度不能超过\(v\),加速度为\(a\),走过\(l\)花费的时间
分类讨论:
\(v^2-v_0^2=2ax\ ->\ x=\frac{v^2-v_0^2}{2a}\)
一直加速\((l<=x)\):\(l=-\frac{1}{2}at^2+v_0t\ ->\ t=\frac{-v_0+\sqrt{v_0^2+2al}}{a}\)
先加速再匀速一段\((l>x)\):\(t=\frac{v-v_0}{a}+\frac{l-x}{v}\)
如果我们速度达到\(w\)的位置在\(d\)之后,或者\(w>=v\),那么答案就是\(f(0,v,a,l)\)
否则仍然要分类讨论:
先单独考虑\(d\)到\(l\),这段时间为\(f(w,v,a,l-d)\)
在\(d\)之前:
假设我们没有\(v\)的限制,加速时间为\(t\),那么这个过程应该是大力先飙车再大力刹车
也就是\(t=t加速+t减速\)
\(t=t加速+t减速到0-t加速到w\)
列方程:\(2a^2t^2-w^2=2ad\ ->\ t=\sqrt{\frac{2ad+w^2}{2a^2}}\)
然后我们看这个加速时间能达到的最大速度有没有达到\(v\)
先加速再减速\((at<=v)\):花费时间为\(t^2-frac{w}{a}\)
先加速然后匀速再减速:花费时间为\(\frac{v}{a}+\frac{v-w}{a}+\frac{d-加速路程-减速路程}{v}\)
#include<bits/stdc++.h> using namespace std; namespace red{ #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define mid ((l+r)>>1) inline int read() { int x=0;char ch,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-')f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } double a,v; double l,d,w,ans,t1,t2; inline double F(double x) { return x*x; } inline double f(double v0,double v,double a,double l) { double s=(v+v0)*(v-v0)/2/a; if(s>=l) return (-v0+sqrt(F(v0)+2*a*l))/a; else return (v-v0)/a+(l-s)/v; } inline void main() { scanf("%lf%lf%lf%lf%lf",&a,&v,&l,&d,&w); double stp=F(w)/2/a; if(w>=v||stp>=d) ans=f(0,v,a,l); else { t2=f(w,v,a,l-d); double tjs=sqrt((2*a*d+F(w))/2/a/a); if(tjs*a<=v) t1=2*tjs-w/a; else { double sf=F(v)/2/a; double sl=(v+w)*(v-w)/2/a; t1=v/a+(v-w)/a+(d-sf-sl)/v; } ans=t1+t2; } printf("%.12f\n",ans); } } signed main() { red::main(); return 0; }
E
一个环,环上一堆山,每个山一个高度,两个山头能互相看见当当且仅当中间没有更高的山
先考虑把最大的挪到\(n\)的位置,然后在\(0\)也补上一个
然后记录\(l[i],r[i]\)表示左右第一个大于自己的位置,和\(c[i]\)表示\([i,r[i])\)中和自己相等的数量
那么每个数字的贡献是\(l[i],r[i]\)两个和\(c[i]\)的数量
注意 \(l[i]==0\)且\(r[i]==n\)时是同一种情况,要减一
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define mid ((l+r)>>1) inline int read() { int x=0;char ch,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-')f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1e6+10; int n,ret,pos; int h[N],a[N],l[N],r[N],c[N]; inline void main() { n=read(); for(int i=0;i<n;++i) { h[i]=read(); if(h[i]>h[pos]) pos=i; } for(int i=0;i<=n;++i) { a[i]=h[(i+pos)%n]; } for(int i=1;i<=n;++i) { l[i]=i-1; while(l[i]&&a[i]>=a[l[i]]) l[i]=l[l[i]]; } for(int i=n-1;~i;--i) { r[i]=i+1; while(r[i]&&a[i]>a[r[i]]) r[i]=r[r[i]]; if(r[i]<n&&a[i]==a[r[i]]) c[i]=c[r[i]]+1,r[i]=r[r[i]]; } for(int i=0;i<n;++i) { ret+=c[i]; if(a[i]<a[0]) { ret+=2; if(!l[i]&&r[i]==n) --ret; } } printf("%lld\n",ret); } } signed main() { red::main(); return 0; }
来源:https://www.cnblogs.com/knife-rose/p/12232747.html