前言
今天考了NOIP11年的一些题,这道题是Day2 T1,考试的时候我只想出了O(n^2)的算法,拿了七十分,下午改了两个多小时,但是还是只写了一个O(nlogn+k)的算法,但是在机房的老爷机上已经可以过了
题目描述
链接在这里 : https://www.luogu.org/problem/P1311
思路
70分
我们可以把每一种主题相同的客栈先用二维数组存下来,同时记录满足费用 <=p 的客栈,再用O(n^2)扫描区间累加
70 pts CODE
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int N=200002; 7 const int M=52; 8 int n,k,p; 9 struct data{ 10 int color; 11 int xf; 12 }jd[N]; 13 int f[M][N],num[M]; 14 int z[N],top=0; 15 bool vis[N]; 16 long long ans=0; 17 bool check(int l,int r) 18 { 19 for (int i=l;i<=r;i++) 20 if (vis[i]) return true; 21 return false; 22 } 23 void cl() 24 { 25 for (int i=0;i<k;i++) 26 { 27 top=0; 28 for (int j=1;j<=num[i];j++) 29 z[++top]=f[i][j]; 30 sort(z+1,z+top+1); 31 for (int j=1;j<=top;j++) 32 for (int t=j+1;t<=top;t++) 33 if (check(z[j],z[t])) ++ans; 34 } 35 } 36 int main() 37 { 38 //freopen("hotel.in","r",stdin); 39 //freopen("hotel.out","w",stdout); 40 scanf("%d %d %d",&n,&k,&p); 41 for (int i=1;i<=n;i++) 42 { 43 scanf("%d %d",&jd[i].color,&jd[i].xf); 44 if (jd[i].xf<=p) vis[i]=true; 45 f[jd[i].color][++num[jd[i].color]]=i; 46 } 47 cl(); 48 printf("%lld",ans); 49 return 0; 50 }
正解(AC)
下来的时候,同机房A掉这道题的苣佬写了ST表,搞得我也写了一个来判断区间之间是否存在满足条件的咖啡店
复杂度 O(nlogn+k) ST表+查询
100 pts CODE
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int N=200010; 7 const int M=52; 8 int n,k,p; 9 struct data{ 10 int color; 11 int xf; 12 }jd[N]; 13 int f[M][N],num[M]; 14 int z[N],top=0; 15 int mx[N][18],lg[N]; 16 int vis[N]; 17 long long ans=0; 18 inline int read() 19 { 20 char ch=getchar(); 21 int x=0;bool flag=false; 22 while (!isdigit(ch)) flag^=!(ch^45),ch=getchar(); 23 while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 24 if (flag) x=-x;return x; 25 } 26 inline void st() 27 { 28 lg[0]=-1; 29 for (int i=1;i<=n;i++) lg[i]=(i&i-1)?lg[i-1]:(lg[i-1]+1); 30 for (int i=1;i<=n;i++) mx[i][0]=vis[i]; 31 for (int j=1;j<=lg[n];j++) 32 for (int i=1;i<=n-(1<<j)+1;i++) 33 mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]); 34 } 35 inline int rmq(int l,int r) 36 { 37 int k=lg[r-l+1]; 38 return max(mx[l][k],mx[r-(1<<k)+1][k]); 39 } 40 inline void cl() 41 { 42 43 for (int i=0;i<k;i++) 44 { 45 top=0; 46 for (int j=1;j<=num[i];j++) 47 z[++top]=f[i][j]; 48 if (top==1) continue; 49 int head=1,tail=2; 50 while (1) 51 { 52 if (rmq(z[head],z[tail])==1) 53 { 54 ans+=top-tail+1; 55 ++head; 56 tail=head+1; 57 } 58 else ++tail; 59 if (head==top||head==top+1) break; 60 if (tail==top+1) 61 { 62 ++head; 63 tail=head+1; 64 } 65 } 66 } 67 } 68 int main() 69 { 70 //freopen("hotel.in","r",stdin); 71 //freopen("hotel.out","w",stdout); 72 n=read(),k=read(),p=read(); 73 for (int i=1;i<=n;i++) 74 { 75 jd[i].color=read(),jd[i].xf=read(); 76 if (jd[i].xf<=p) vis[i]=1; 77 f[jd[i].color][++num[jd[i].color]]=i; 78 } 79 st(); 80 cl(); 81 printf("%lld",ans); 82 return 0; 83 }