Bestcoder round#34 解题报告

1001 Go to movies

枚举暴力一发就行。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;
int n,m;
int main()
{
    while (cin>>n>>m)
    {
        int ans=1100000;
        for (int i=1;i<=m;i++)
        {
            int a,b;
            cin>>a>>b;
            int d=n/a;
            if (n%a) d++;
            ans=min(ans,d*b);
        }
        cout<<ans<<endl;
    }
    return 0;
}

1002 Building Blocks

首先我们很容易知道,题目无解当且仅当 h[i]<WH 。对于一段长为 W 的序列,高度小于H部分的高度和为 h[i](h[i]<H) ,高度大于 H 部分的高度和为h[i](h[i]>H),而最小的移动数应为 max(h[i](h[i]<H),h[i](h[i]>H)) 。然后我们线性扫一遍就行了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;
typedef long long LL;
LL n,w,h;
LL sum,a[151000];
LL ans;
LL l,r;
LL cal()
{
    LL res=l+r-min(l,r);
    return res;
}
int main()
{
    while (scanf("%I64d %I64d %I64d",&n,&w,&h)==3)
    {
        sum=0;
        memset(a,0,sizeof(a));
        for (int i=1;i<=n;i++)
            scanf("%I64d",&a[i+w]),sum+=a[i+w];
        if (sum<w*h)
        {
            printf("-1\n");
            continue;
        }
        l=0,r=0;
        for (int i=1;i<=w;i++)
        {
            if (a[i]<h) l+=h-a[i];
            else r+=a[i]-h;
        }
        ans=cal();

        for (int i=1;i<=w+n;i++)
        {
            if (a[i]<h) l-=h-a[i];
            else r-=a[i]-h;
            if (a[i+w]<h) l+=h-a[i+w];
            else r+=a[i+w]-h;
            ans=min(ans,cal());
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

1003 Building Blocks II

判断无解的方法与上题相同。考虑一段序列,不难发现,使它移动次数最少的高度应为整个序列的平均高度(同时还得比 H 高)。由于平均高度不一定为整数,所以我们还得考虑取整后+1这一高度。上题由于高度确定,所以可以O(1)维护两部分和的值,而此题不确定,所以我们需要利用树状数组来维护这一部分的和。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;
typedef long long LL;
const int maxn=60000;
LL nu[maxn+10];
LL height[maxn+10];
const LL INF=1e18;
inline int lowbit(int x)
{
    return (x&-x);
}
void add(LL *fenwick,int x,LL value)
{
    for (int i=x;i<=maxn;i+=lowbit(i))
        fenwick[i]+=value;
}
LL get(LL *fenwick,int x)
{
    LL sum=0;
    for (int i=x;i;i-=lowbit(i))
        sum+=fenwick[i];
    return sum;
}
LL nowh;
int n;
LL h,w;
LL v[3*maxn+10];
LL ansx,ans,sum;
void check(LL x)
{
    if (x<h||x*w>sum) return;
    LL minn=x*get(nu,x-1)-get(height,x-1),maxx=get(height,55001)-get(height,x)-x*(get(nu,55001)-get(nu,x));
    LL res=max(minn,maxx);
    if (res<ans||((res==ans)&&(x>ansx)))
    {
        ans=res;
        ansx=x;
    }
}
int main()
{
    while (scanf("%d %I64d %I64d",&n,&w,&h)==3)
    {
        memset(nu,0,sizeof(nu));
        memset(height,0,sizeof(height));
        for (int i=0;i<3*maxn+10;i++)
            v[i]=1;
        sum=0;
        h++;
        for (int i=1;i<=n;i++)
            scanf("%I64d",&v[i+maxn]),++v[i+maxn],sum+=v[i+maxn];
        if (sum<w*h)
        {
            printf("-1\n");
            continue;
        }
        nowh=w;
        add(nu,1,w);
        add(height,1,w);
        ans=INF;
        ansx=0;
        for (int i=maxn+1;i<=n+maxn+w;i++)    
        {

            nowh-=v[i-w];
            add(nu,v[i-w],-1);
            add(height,v[i-w],-v[i-w]);
            nowh+=v[i];
            add(nu,v[i],1);
            add(height,v[i],v[i]);
            LL x=nowh/w;
            check(x);
            check(x+1);
            check(h);
        }
        if (ans==INF) printf("-1\n");
        else printf("%I64d %I64d\n",ansx-1,ans);
    }
    return 0;
} 

1004 Go to movies II

静态的逆序对我们可以用树状数组维护,由于此题中有插入和删除操作,会改变相对位置,所以需要利用数据结构套数据结构的方式。由于此题可以 O(nn) 搞,所以我们就用块状链表套树状数组实现。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;

const int maxn=21000;
inline int lowbit(int x)
{
    return (x&-x);
}
void add(int *fenwick,int x,int value)
{
    for (int i=x;i<=maxn;i+=lowbit(i))
        fenwick[i]+=value;
}
int get(int *fenwick,int x)
{
    int sum=0;
    for (int i=x;i;i-=lowbit(i))
        sum+=fenwick[i];
    return sum;
}
const int m=350;
struct data
{
    int s,a[2*m+5];
    int c[21000];
    data *next;
    data()
    {
        memset(c,0,sizeof(c));
        next=NULL;
    }
};
data *root;
void insert(int x,int pos)
{
    if (root==NULL)
    {
        root=new(data);
        root->s=1;
        root->a[1]=x;
        add(root->c,x,1);
        return ;
    }
    data *k=root;
    while (pos>k->s && k->next!=NULL)
    {
        pos-=k->s;
        k=k->next;
    }
    memmove(k->a+pos+1,k->a+pos,sizeof(int)*(k->s-pos+1));
    k->s++;
    k->a[pos]=x;
    add(k->c,x,1);
    if (k->s==2*m)
    {
        data *t=new(data);
        t->next=k->next;
        k->next=t;
        memcpy(t->a+1,k->a+m+1,sizeof(int)*m);
        for (int i=1;i<=m;i++)
        {
            add(k->c,t->a[i],-1);
            add(t->c,t->a[i],1);
        }
        t->s=k->s=m;
    }
}
void del(int pos)
{
    data *k=root;
    while (pos>k->s && k->next!=NULL)
    {
        pos-=k->s;
        k=k->next;
    }
    add(k->c,k->a[pos],-1);
    memmove(k->a+pos,k->a+pos+1,sizeof(int)*(k->s-pos));
    k->s--;
}
int find(int pos)
{
    data *k=root;
    while (pos>k->s && k->next!=NULL)
    {
        pos-=k->s;
        k=k->next;
    }
    return (k->a[pos]);
}
void destroy(data *k)
{
    if (k->next!=NULL)
        destroy(k->next);
    delete(k);
}
int cal(int pos)
{
    int res=0;
    data *k=root;
    int x=find(pos);
    while (pos>k->s && k->next!=NULL)
    {
        pos-=k->s;
        res+=get(k->c,20000)-get(k->c,x);
        k=k->next;
    }
    for (int i=1;i<pos;i++)
        if (k->a[i]>x) res++;
    for (int i=pos+1;i<=k->s;i++)
        if (k->a[i]<x) res++;
    while (k->next!=NULL)
    {
        k=k->next;
        res+=get(k->c,x-1)-get(k->c,0);
    }
    return res;
}
int ans;
int n,q;
int main()
{
    while (scanf("%d %d",&n,&q)==2)
    {
        root=NULL;
        ans=0;
        for (int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            insert(x,i);    
            ans+=cal(i);
        }
        for (int i=1;i<=q;i++)
        {
            int op;
            scanf("%d",&op);
            if (op==0)
            {
                int x,y;
                scanf("%d %d",&x,&y);
                x++;
                insert(y,x);
                ans+=cal(x);
            }
            else
            {
                int x;
                scanf("%d",&x);
                ans-=cal(x);
                del(x);
            }
            printf("%d\n",ans);
        }
        destroy(root);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值