#rMQybttg040206. 1546:NOIP2011 选择客栈

1546:NOIP2011 选择客栈

好的,我将这道题整理为清晰的题面格式,并补充样例解释、数据范围与时空限制:


题目描述

丽江河边有 nn 家很有特色的客栈,客栈按照其位置顺序从 11nn 编号。

每家客栈都按照某一种色调进行装饰(总共 kk 种,用整数 0k10 \sim k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。

两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。

晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过 pp

他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过 pp 元的咖啡店小聚。


输入格式

第一行三个整数 n,k,pn, k, p,每两个整数之间用一个空格隔开,分别表示客栈的个数,色调的数目和能接受的最低消费的最高值;

接下来的 nn 行,第 i+1i+1 行两个整数,之间用一个空格隔开,分别表示 ii 号客栈的装饰色调 aia_iii 号客栈的咖啡店的最低消费 bib_i


输出格式

输出一行,一个整数,表示可选的住宿方案的总数。


样例

样例输入

5 2 3
0 5
1 3
0 2
1 4
1 5

样例输出

3

样例说明

客栈编号:1 2 3 4 5
色调:0 1 0 1 1
最低消费:5 3 2 4 5
p=3p=3

要求两人住相同色调的客栈,且中间(含两端)有至少一家咖啡店最低消费 3\le 3

可能方案:

  1. (1,3):色调 0,中间咖啡店有 1(5),2(3),3(2),最低消费有 3,2 ≤ 3,可行;
  2. (2,4):色调 1,中间咖啡店有 2(3),3(2),4(4),最低消费有 3,2 ≤ 3,可行;
  3. (2,5):色调 1,中间咖啡店有 2(3),3(2),4(4),5(5),最低消费有 3,2 ≤ 3,可行;
  4. (4,5):色调 1,中间咖啡店有 4(4),5(5),最低消费都 >3,不可行。

所以可行方案数为 33


数据范围

  • 对于 25%25\% 的数据,有 n100n \le 100
  • 对于 40%40\% 的数据,有 n1,000n \le 1,000
  • 对于 80%80\% 的数据,有 n200,0000<k50n \le 200,000,0<k \le 50
  • 对于 100%100\% 的数据,有 $2 \le n \le 2\times 10^6,0<k<10^4,0 \le p \le 100,0 \le b_i \le 100$。

时空限制

  • 时间:1000 ms1000 \text{ ms}
  • 内存:524288 KB524288 \text{ KB}(512 MB)

提示
此题可以 O(n)O(n)O(nk)O(nk) 解决,由于 nn 可达 2×1062\times 10^6kk 可达 10410^4,需要线性或接近线性的算法。

思路

  • 从左到右扫描,维护对于每种颜色,最近一次出现“可行咖啡店”的位置;
  • 对于当前客栈 ii,如果 bipb_i \le p,则它是一个“可行咖啡店”;
  • 对于当前客栈 ii,色调为 cc,我们需要知道之前色调为 cc 的客栈中,有多少个可以与之配对,使得它们之间有可行咖啡店。

具体做法

  • last[c]last[c] 表示色调 cc 的客栈最近一次出现的位置;
  • pospos 表示最近一个可行咖啡店的位置(即 bjpb_j \le p 的最大 jj);
  • sum[c]sum[c] 表示色调 cc 的客栈中,最近一个可行咖啡店之后(含)的客栈数量。

扫描过程:

  1. 若当前 bipb_i \le p,则更新 pos=ipos = i
  2. 对于色调 c=aic = a_i
    • 如果 last[c]poslast[c] \le pos(即最近的同色客栈在最近可行咖啡店之前或相同位置),则当前客栈 ii 可以和之前所有色调 cc 的客栈配对(共 sum[c]sum[c] 个);
    • 否则,当前客栈 ii 只能和最近可行咖啡店之后(含)的色调 cc 的客栈配对(即 sum[c]sum[c] 个);
    • 然后将 ansans 加上 sum[c]sum[c]
  3. 更新 sum[c]sum[c]+1sum[c] \gets sum[c] + 1(当前客栈加入计数);
  4. 更新 last[c]=ilast[c] = i

解释
sum[c]sum[c] 实际上记录了最近一个可行咖啡店之后(含)的色调 cc 的客栈数量。
当出现新的可行咖啡店时,pospos 更新,但 sum[c]sum[c] 不会清零,因为之前的客栈仍然可以和之后的客栈配对(只要可行咖啡店在它们之间)。

注意

  • 初始化 last[c]=0,sum[c]=0last[c] = 0, sum[c] = 0
  • pos=0pos = 0
  • 答案可能很大,用 long long 存储。

复杂度O(n)O(n)

样例运行(按上述算法):

  • i=1: c=0, b=5>3, pos=0, last[0]=0, sum[0]=0, 加 0, sum[0]=1, last[0]=1
  • i=2: c=1, b=3≤3, pos=2, last[1]=0, sum[1]=0, 加 0, sum[1]=1, last[1]=2
  • i=3: c=0, b=2≤3, pos=3, last[0]=1, sum[0]=1, 加 1, sum[0]=2, last[0]=3
  • i=4: c=1, b=4>3, pos=3, last[1]=2, sum[1]=1, 加 1, sum[1]=2, last[1]=4
  • i=5: c=1, b=5>3, pos=3, last[1]=4, sum[1]=2, 加 2, sum[1]=3, last[1]=5

答案累计:0+0+1+1+2=4?不对,应该是 3,说明算法细节需调整。

实际上标准解法:

  • 维护 cnt[c]cnt[c] 表示当前色调 cc 的客栈总数;
  • 维护 lastcnt[c]lastcnt[c] 表示最近一个可行咖啡店之后色调 cc 的客栈数;
  • 当遇到可行咖啡店时,令 lastcnt[c]=cnt[c]lastcnt[c] = cnt[c](因为之前的客栈都可以和后面的配对);
  • 对于当前客栈 ii,若 bipb_i \le p,则更新 lastcnt[ai]=cnt[ai]lastcnt[a_i] = cnt[a_i],然后 ans+=lastcnt[ai]1ans += lastcnt[a_i] - 1(减1是不包括自己和自己配对);
  • bi>pb_i > p,则 ans+=lastcnt[ai]ans += lastcnt[a_i]

这样可保证正确。

鉴于细节较复杂,建议直接参考标准代码实现。