选择客栈(NOIP2011)

有趣的题
不得不承认这道题还是比较有意思的。
其实正解并不是非常好想。
首先,我们先异想天开一下。
我们能不能用线段树?
什么?
其实就是把价格转换成一个vis函数。即0代表不符合,1代表符合。
然后对vis建线段树,方便枚举时查询。
然后枚举,我们读入的时候建立一个vector,然后同一种颜色的放一块,方便枚举。
的确很异想天开,不是吗?
我测试了一下,60分。
要不换成ST?
歇菜吧!老哥!我们来看看正解还是怎么写的。
我们第一反应一定是枚举。
但是我们一对点一对点的枚举一定会超时的。
所以我们可以考虑只枚举一个点。
我们弄三个数组:sum[]、cnt[]、last[]
分别表示当前点的对数,当前颜色的点的数量,该颜色上一个点的标号。
为什么要这么做?
我们来想一下,当前这个点能有多少对?
那么我们就看最近的一个符合条件的酒馆的坐标,如果这个酒馆在当前点和该颜色上一个点之间,那么我们能组成的对数就是cnt[last[]]。如果不在,那么就是就是上一个该颜色的点组成的对数,因为当前点在它的后面。
这样的话一个递推就形成了。
又因为我们每次只需要一种颜色中的一个点,所以我们的数组的下标都是颜色。
代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k,p;
int col,mo;
int cnt[55],last[55],sum[55];
int cur,ans;
int main(){
    memset(cnt,0,sizeof(cnt));
    memset(last,0,sizeof(last));
    memset(sum,0,sizeof(sum)); 
    cur=0;
    ans=0;
    scanf("%d%d%d",&n,&k,&p);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&col,&mo);
        if(mo<=p){
            cur=i;
        }
        if(cur>=last[col]){
            sum[col]=cnt[col];
        }
        cnt[col]++;
        ans+=sum[col];
        last[col]=i;
    }
    printf("%d",ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值