HDU 3474

本文介绍了一种解决特定项链切割问题的有效算法。该问题要求切割项链后,确保取出的水晶数量不少于珍珠数量。通过使用单调队列来优化查找过程,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给你一条项链,让你切开,然后将上面的水晶和珍珠拿下来再连起来,但现在只问你你有多少种切割方法使得你拿下来的水晶数量一定不少于珍珠数量,只能一个一个拿。

分析:最先想到的肯定是暴力枚举每个断点然后查询len长度的C和J的个数比较一下,看一下范围项链长度2<=len<=10^6,肯定会超,因为任何时候都要满足一个条件,就是sum(C)>=sum(J)也就是sum(C)-sum(J)>=0;我们可以将sum(C)-sum(J)用sum[i]来表示,表示前i个珠子里水晶数量与珍珠的差值,显然我们可以看出sum[i]-sum[j]表示的是从j+1开始到i这个珠子的差值和,而我们要找的是len长度中的差值全部不小于0的那一段,这显然用单调队列来实现只要保证min(sum[i]~sum[i-len+1])-sum[i-len]就可以了,问题解决了,后面写的是后发现还要反过来求一次,最后将两次的位置去重就好了,这个细节卡了我一个下午,校对位置的时候错了,一直没发现,后来模拟多点数据就发现错了,就这样贡献了10+wa啊,我是从0开始的,别人好像为了去重方便就直接从1开始,我从0开始,后面回差一位,就果断在后面加个0对位,一交果断AC。

还有今天突发奇想的想用二分优化单调队列,结果写完后更慢了,坑爹啊。

Run IDSubmit TimeJudge StatusPro.IDExe.TimeExe.MemoryCode Len.LanguageAuthor
43901222011-08-11 20:28:07Accepted3474453MS28592K1947 BC++xym2010

下面是我的实现代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000005;
struct queuey
{
    int flag,key;
}q[maxn*2];
int r,f;
void insert(int flag,int key)
{
    while(r>f&&key<q[r].key)
        r--;
    q[++r].flag=flag;
    q[r].key=key;
}
void init()
{
    r=f=0;
}
char s[2*maxn],ss[2*maxn];
bool vd[2*maxn];
int sum[2*maxn];
int main()
{
    int c,len,count=0,d=0;    
    scanf("%d",&c);
    while(c--)
    {
        d++;
        scanf("%s",s);
        len=strlen(s);
        for(int i=0;i<len;i++)
            ss[i]=s[i];
        for(int i=0;i<len;i++)
            ss[len+i]=s[i];
        sum[0]=ss[0]=='C'?1:-1;
        init();
        for(int i=1;i<2*len;i++)
            sum[i]=sum[i-1]+(ss[i]=='C'?1:-1);
        count=0;
        memset(vd,0,sizeof(vd));
        for(int i=0;i<2*len;i++)
        {
            insert(i,sum[i]);
            while(q[f+1].flag<=i-len&&r>f)
                f++;
            if(i-len>=0)
            {
                if(q[f+1].key>=sum[i-len])
                    if(vd[i]==0)
                    {
                        count++;
                        vd[i]=1;
                    }
            }
        }
        init();
		sum[2*len]=0;
        sum[2*len-1]=ss[2*len-1]=='C'?1:-1;
        for(int i=2*len-2;i>=0;i--)
        {
            sum[i]=sum[i+1]+(ss[i]=='C'?1:-1);
        }
        for(int i=2*len;i>0;i--)
        {
            insert(i,sum[i]);
            while(q[f+1].flag>=i+len&&r>f)
                f++;
            if(i<=len)
            {
                if(q[f+1].key>=sum[i+len])
                    if(vd[i+len-1]==0)
                    {
                        count++;
                        vd[i+len-1]=1;
                    }
            }
        }
        printf("Case %d: %d\n",d,count);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值