bzoj 4415: [Shoi2013]发牌

本文介绍了一种通过二分搜索与树状数组结合的方法来解决特定发牌顺序问题的算法。该算法首先利用树状数组记录每张牌的位置,再通过二分查找确定每次发牌的位置,最终输出发牌顺序。此算法的时间复杂度为O(nlog²n)。

题意:一沓牌从1到n,每次把ri张牌从牌堆顶放到牌堆底,然后发出牌堆顶的牌。求发牌顺序。
题解:二分+树状数组。树状数组记录到某个位置有几张牌,然后每次记录现在是第几张牌。二分找出位置然后再更新就好了。O(nlog2n)好慢。。。
代码:

#include<cstdio>
#include<cstring>

int n,s[700010];//存在几张牌

int lb(int x)
{
    return x&-x;
}
void add(int x,int y)
{
    for(int i=x;i<=n;i+=lb(i))
    s[i]+=y;
}
int get(int x)
{
    int ans=0;
    for(int i=x;i>0;i-=lb(i))
    ans+=s[i];
    return ans;
}
int fd(int x)
{
    int l=1,len=n;
    while(len)
    {
        int md=l+(len>>1);
        if(get(md)<x)
        {
            l=md+1;
            len=len-(len>>1)-1;
        }
        else
        len>>=1;
    }
    return l;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    add(i,1);
    int now=0;
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        x=x%(n+1-i);
        now=(now+x)%(n+1-i);
        int hh=fd(now+1);
        printf("%d\n",hh);
        add(hh,-1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值