码迷,mamicode.com
首页 > 其他好文 > 详细

CF5

时间:2020-01-25 10:18:35      阅读:126      评论:0      收藏:0      [点我收藏+]

标签:char   efi   str   math   signed   结构   cin   max   指针   

A

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

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

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

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

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;
}

CF5

标签:char   efi   str   math   signed   结构   cin   max   指针   

原文地址:https://www.cnblogs.com/knife-rose/p/12232747.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!