Atcoder Beginner Contest 128解题报告

A Apple Pie

#include
using namespace std;
int a,b;
int main()
{
    cin>>a>>b;
    cout<<(a*3+b)/2<

B Guidebook

#include
using namespace std;
int n;
struct node
{
    string a;
    int b,id;
    bool operator<(const node&o)const
    {
        if(a==o.a) return b>o.b;
        return a>p[i].a>>p[i].b;
        p[i].id=i;
    }
    sort(p+1,p+1+n);
    for(int i=1;i<=n;i++)
        printf("%d\n",p[i].id);
}

C Switches
状态压缩,二进制位1表示这个位置的开关被打开,为0表示被关闭

#include
using namespace std;
int n,m,a[15];
bool vis[15];
vectorv[15];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        while(x--)
        {
            int y;
            scanf("%d",&y);
            v[i].push_back(y);
        }
    }
    for(int i=1;i<=m;i++)
        scanf("%d",&a[i]);
    int ans=0;
    for(int i=0;i<1<

D equeue
数据范围很小,因为每次取可以左右取,只要枚举左边去了多少个,右边去了多少个,把手中的数当然取完后再弹出来事最优的。时间复杂度O(n^2)也过得去,所以就暴力枚举了。无脑开了MAXN=50,WA了一发。

#include
#define ll long long
using namespace std;
int n,k;
ll a[555];
priority_queue,greater >q;
int main()
{
    ll ans=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=0;i<=min(n,k);i++)
        for(int j=0;i+j<=min(n,k);j++)
    {
        for(int h=1,t=1;h<=i;h++,t++)
            q.push(a[t]);
        for(int h=1,t=n;h<=j;h++,t--)
            q.push(a[t]);
        int p=k-i-j;
        while(!q.empty()&&p>0&&q.top()<0)
        {
            q.pop();
            p--;
        }
        ll res=0;
        while(!q.empty())
        {
            res+=q.top();
            q.pop();
        }
        ans=max(ans,res);
    }
    printf("%lld\n",ans);
}

E Roadwork
把q个人出发的时间线排序(当然给出的时间线是有序的),推测每个点x会阻挡那一段时间出发的人,不过不能暴力遍历这段时间被哪些点阻挡,但可以在有序的时间段内找出一个l,r位置,在按顺序遍历q个人时,如果碰到x的l位置,则把x插入集合,碰到r位置,则把x从集合中删除,因为较小的x一定会先阻挡某个人,所以答案是集合中最小的数,如果集合中没有这样的数,答案就是-1,又因为一个位置可以是多个x的l位置或者多个x的r位置,因此我这里用队列维护了一个多个集合。
PS:一开始把队列开在了结构体里,然后每次运行的时间stl就莫名的会让程序卡很久,就莫名的T了几发。

#include
using namespace std;
const int N=2e5+5;
int n,q,b[N],ans[N];
int flag,t[4*N],hs[N];
queueqa[N],qb[N];
struct node
{
    int s,t,x;
}a[N];
bool cmp(node a,node b)
{
    return a.x>1;
    if(x<=m) fix(l,m,k<<1,x);
    else fix(m+1,r,k<<1|1,x);
    t[k]=t[k<<1]+t[k<<1|1];
}
void del(int l,int r,int k,int x)
{
    if(l==r)
    {
        t[k]--;
        if(l==flag) flag=0;
        return;
    }
    int m=l+r>>1;
    if(x<=m) del(l,m,k<<1,x);
    else del(m+1,r,k<<1|1,x);
    t[k]=t[k<<1]+t[k<<1|1];
}
int query(int l,int r,int k)
{
    if(l==r) return hs[l];
    int m=l+r>>1;
    if(t[k<<1]) return query(l,m,k<<1);
    else if(t[k<<1|1]) return query(m+1,r,k<<1|1);
    return -1;
}
int read()
{
    char c=getchar();int x=0,f=1;
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    if(c=='-') f=-1,c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return x*f;
}
int main()
{
    n=read();q=read();
    for(int i=1;i<=n;i++)
        a[i].s=read(),a[i].t=read(),a[i].x=read(),hs[i]=a[i].x;
    sort(hs+1,hs+1+n);
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=q;i++)
        b[i]=read();
    for(int i=n;i>=1;i--)
    {
        int s=a[i].s,t=a[i].t;
        int l=lower_bound(b+1,b+1+q,s-a[i].x)-b,r=lower_bound(b+1,b+1+q,t-a[i].x)-b-1;
        if(l>r) continue;
        qa[l].push(i);
        qb[r].push(i);
    }
    for(int i=1;i<=q;i++)
    {
        while(!qa[i].empty())
        {
            fix(1,n,1,qa[i].front());
            qa[i].pop();
        }
        if(!flag)
            ans[i]=query(1,n,1);
        else ans[i]=hs[flag];
        while(!qb[i].empty())
        {
            del(1,n,1,qb[i].front());
            qb[i].pop();
        }
    }
    for(int i=1;i<=q;i++)
        printf("%d\n",ans[i]);
}

F Frog Jump
任取个a,b,把遍历的位置列一下a,a-b,2*a-b,2*a-2*b…x*a-(x-1)*b,就有x*a-(x-1)*b=n-1。设p=a-b,则b=a-p,就有x*a-(x-1)*(a-p)=n-1,于是又(n-1-a)%p=0,因为p是(n-1-a)的因子,而相对于1e5的数据,因子的个数就比较少了。枚举一下a,再考虑枚举(n-1-a)所有的因子,我这里用数论分块logn进行枚举。当然枚举了p,也不能暴力去计算答案呀,因此再用前缀和和后缀和分块进行一下预处理,当p<=sqrt(n)时,可以O(1)从前缀后缀和中得出答案,当p>sqrt(n)就算暴力去跑,时间消耗也很小了。
当然,还没有结束,因为还要考虑怎么避开选择的a,b会使得跳的时候不会出现重合的情况,在图上画一下,发现可以把这个过程分解成两个部分,一个是从a,一直加p(p=a-b)直到n-1的位置,一个是从n-1-a位置开始,一直减b,直到0的位置结束,期间只要保持两个部分不相交就行了,设x=a,y=n-1-a,当x>y的时候,显然不会相交,当x=y显然已经相交了,当x PS:不知咋滴莫名wa了1个小范围的案例,于是当n较小时就瞎暴力枚举了一下,如有大佬发现错误,请指点指点。

#include
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,a[N];
ll pre[322][N],bk[322][N];
sets;
void solve()
{
    ll ans=0;
    for(int x=1;x=0;k-=x-y)
        {
            if(s.count(k)) {res=0;break;}
            res+=a[k];
        }
        s.clear();
        ans=max(ans,res);
    }
    printf("%lld\n",ans);
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i=0;j-=i)
            bk[i][j]=a[j];
        for(int j=n-1-i;j>=0;j--)
            bk[i][j]+=bk[i][j+1];
    }
    for(int i=1;iy) break;
                r=y/(y/l);
            }
        }
        else if(s>0)
        {
            int l=1,r=1;
            while(l<=y)
            {
                if(y%l==0&&s%l!=0&&ly) break;
                r=y/(y/l);
            }
        }
    }
    printf("%lld\n",ans);
}
/*
a=6,b=4
11
0 -4 0 -99 31 14 -15 -39 43 18 0
*/


你可能感兴趣的:(Atcoder Beginner Contest 128解题报告)