1878: [SDOI2009]HH的项链

1878: [SDOI2009]HH的项链

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 4420  Solved: 2199
[Submit][Status][Discuss]

Description

HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一
段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一
个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只
好求助睿智的你,来解决这个问题。

Input

第一行:一个整数N,表示项链的长度。 
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。 
第三行:一个整数M,表示HH询问的个数。 
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。

Output

M行,每行一个整数,依次表示询问对应的答案。

Sample Input

6
1 2 3 4 3 5
3
1 2
3 5
2 6

Sample Output

2
2
4

 

//离线算法的话,比较好写,树状数组,或线段树维护一个前缀和

在线算法听说是主席树,目前还不会,以后会了,一定更

离线树状数组,思路是,先对贝壳数组模拟一个链表,nex[i] 记录每个位置右边最近的与该位置贝壳种类相同的贝壳的位置。

然后,pos[i] 记录 i 种类的贝壳最靠左的位置,然后,对每个存在种类的贝壳的最靠左位置(就是pos[i]),建一个树状数组,位置上有最靠左的贝壳就是 1 ,否则是0,这样是为了统计区间内的种类数!

然后,所有查询按左端点排序,枚举左端点,靠前面的链表更新树状数组,求前缀和。

其实感觉最大的耗时在于对询问的排序。。。mlog(m)

 1 /**************************************************************
 2     Problem: 1878
 3     User: happy_code
 4     Language: C++
 5     Result: Accepted
 6     Time:1780 ms
 7     Memory:8908 kb
 8 ****************************************************************/
 9  
10 #include <iostream>
11 #include <stdio.h>
12 #include <string.h>
13 #include <algorithm>
14 using namespace std;
15 #define MXN 50005
16 #define MXM 200005
17 struct Que
18 {
19     int l,r;
20     int id;
21     int ans;
22 }q[MXM];
23  
24 int n,m;
25 int a[MXN];
26 int pos[1000005];
27 int nex[MXN];
28 int tree[MXN];
29  
30 int lowbit(int x){return x&(-x);}
31 bool cmp1(const Que &a,const Que &b)
32 {
33     return a.l<b.l;
34 }
35 bool cmp2(const Que &a,const Que &b)
36 {
37     return a.id<b.id;
38 }
39  
40 void update(int x,int k)
41 {
42     for (int i=x;i<=n;i+=lowbit(i))
43         tree[i]+=k;
44 }
45  
46 int query(int x)
47 {
48     int res=0;
49     for (int i=x;i>0;i-=lowbit(i))
50         res+=tree[i];
51     return res;
52 }
53  
54 int main()
55 {
56     scanf("%d",&n);
57     for (int i=1;i<=n;i++)
58         scanf("%d",&a[i]);
59     for (int i=n;i>0;i--)
60     {
61         nex[i]=pos[a[i]];
62         pos[a[i]]=i;
63     }
64     for (int i=0;i<1000005;i++) //初始化
65         if (pos[i]) update(pos[i],1);
66  
67  
68     scanf("%d",&m);
69     for (int i=0;i<m;i++)
70     {
71         scanf("%d%d",&q[i].l,&q[i].r);
72         q[i].id=i;
73     }
74     sort(q,q+m,cmp1);
75  
76     int l=1;
77     for (int i=0;i<m;i++)
78     {
79         while (l<q[i].l)
80         {
81             if (nex[l]) update(nex[l],1);
82             l++;
83         }
84         q[i].ans = query(q[i].r)-query(q[i].l-1);
85     }
86  
87     sort(q,q+m,cmp2);
88     for (int i=0;i<m-1;i++)
89         printf("%d\n",q[i].ans);
90     printf("%d\n",q[m-1].ans);
91     return 0;
92 }
View Code

 

转载于:https://www.cnblogs.com/haoabcd2010/p/7282143.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您的需求很清晰明了,我来帮您解决这个问题。 以下是 JAVA 代码实现: ```java import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class DeviceWorkTimeChecker { /** * 判断设备在某一天的工作时间段是否满足某工序所需工作时间,并返回满足条件的空闲时间段 * * @param workTimeStr 设备的日常工作时间段字符串,格式为HH:mm-HH:mm;HH:mm-HH:mm;HH:mm-HH:mm * @param freeTimeStr 设备的未工作的空闲时间段字符串,格式为HH:mm-HH:mm;HH:mm-HH:mm;HH:mm-HH:mm;HH:mm-HH:mm * @param workTimeInMin 某工序需要的工作时间(单位为分钟) * @return 如果设备在某一天的工作时间段满足某工序所需工作时间,则返回true和满足条件的空闲时间段的开始时间HH:mm,否则返回false */ public static List<String> checkDeviceWorkTime(String workTimeStr, String freeTimeStr, int workTimeInMin) { List<String> freeTimeList = splitTimeStr(freeTimeStr); List<String> workTimeList = splitTimeStr(workTimeStr); List<String> workTimeIntervals = getWorkTimeIntervals(workTimeList, freeTimeList); for (String interval : workTimeIntervals) { if (isIntervalLongEnough(interval, workTimeInMin)) { List<String> result = new ArrayList<>(); result.add("true"); result.add(interval.split("-")[0]); return result; } } List<String> result = new ArrayList<>(); result.add("false"); return result; } /** * 将时间段字符串分割成时间段列表 * * @param timeStr 时间段字符串,格式为HH:mm-HH:mm;HH:mm-HH:mm;HH:mm-HH:mm * @return 时间段列表,例如["HH:mm-HH:mm", "HH:mm-HH:mm", "HH:mm-HH:mm"] */ private static List<String> splitTimeStr(String timeStr) { String[] timeArray = timeStr.split(";"); List<String> timeList = new ArrayList<>(); for (String time : timeArray) { timeList.add(time); } return timeList; } /** * 获取工作时间段列表(不包含空闲时间段) * * @param workTimeList 设备的日常工作时间段列表 * @param freeTimeList 设备的未工作的空闲时间段列表 * @return 工作时间段列表(不包含空闲时间段) */ private static List<String> getWorkTimeIntervals(List<String> workTimeList, List<String> freeTimeList) { List<String> workTimeIntervals = new ArrayList<>(); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); try { for (String workTime : workTimeList) { Date workStartTime = sdf.parse(workTime.split("-")[0]); Date workEndTime = sdf.parse(workTime.split("-")[1]); boolean isWorkTime = true; for (String freeTime : freeTimeList) { Date freeStartTime = sdf.parse(freeTime.split("-")[0]); Date freeEndTime = sdf.parse(freeTime.split("-")[1]); if (workStartTime.compareTo(freeStartTime) >= 0 && workEndTime.compareTo(freeEndTime) <= 0) { isWorkTime = false; break; } } if (isWorkTime) { workTimeIntervals.add(workTime); } } } catch (ParseException e) { e.printStackTrace(); } return workTimeIntervals; } /** * 判断时间段是否超过指定长度 * * @param timeInterval 时间段字符串,格式为HH:mm-HH:mm * @param durationInMin 指定长度(单位为分钟) * @return 如果时间段超过指定长度,则返回true,否则返回false */ private static boolean isIntervalLongEnough(String timeInterval, int durationInMin) { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); try { Date startTime = sdf.parse(timeInterval.split("-")[0]); Date endTime = sdf.parse(timeInterval.split("-")[1]); long durationInMs = durationInMin * 60 * 1000L; if (endTime.getTime() - startTime.getTime() >= durationInMs) { return true; } } catch (ParseException e) { e.printStackTrace(); } return false; } } ``` 您可以通过以下代码来测试: ```java public static void main(String[] args) { String workTimeStr = "09:00-12:00;13:00-18:00"; String freeTimeStr = "10:00-11:00;15:00-16:00"; int workTimeInMin = 120; List<String> result = DeviceWorkTimeChecker.checkDeviceWorkTime(workTimeStr, freeTimeStr, workTimeInMin); System.out.println("是否满足工序时间:" + result.get(0)); System.out.println("空闲时间段的开始时间:" + result.get(1)); } ``` 输出结果将会是: ``` 是否满足工序时间:true 空闲时间段的开始时间:09:00 ``` 希望我的回答能够帮助您!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值