「一本通 4.2 练习 3」选择客栈 (loj2597)(noip2011)
思路:
这道题简单来说就是,选出两个旅店的色调相同且中间(包括两边)存在价格小于p的旅店的个数。
于是很容易想到,在读入时进行预处理将每一种色调的酒店归为一类。
然而如何去判断两个酒店中间有没有价格小于p的酒店呢?
其实只需要定义一个前缀和sum[i]表示从1到i之间的价格小于等于p的酒店个数,那么i和j位置的两个酒店之间符合要求的咖啡馆个数为sum[j] - sum[i-1],只要它不为0,就是符合条件的。
但是,每一个色调的数组大小不好开,在这里我用的是STL的vector(在这道题里vector并不算慢,进行200万次push_back操作只用了100+ms)
在枚举时只要发现了一对i, j 那么j之后的所有酒店均可以与i结合凑成一堆,于是整体加上,直接break
最后输出累加结果即可。时间复杂度约为400 × k
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<vector> using namespace std; const int maxk = 10010; const int maxn = 2000010; inline void qread(int &x){ x = 0; register int ch = getchar(), flag = 0; while(ch < '0' || ch > '9') { if(ch == '-') flag = 1; ch =getchar(); } while(ch >='0' && ch <='9'){ x = 10 * x + ch - 48; ch = getchar(); } if(flag) x = -x; } int n, k, p, cl, co; long long ans; vector<int> v[maxk]; int sum[maxn]; int main(void) { qread(n); qread(k); qread(p); for(int i=1; i<=n; ++i){ qread(cl); cl++; qread(co); sum[i] = sum[i-1] + (co<=p); v[cl].push_back(i); } for(int i=1; i<=k; ++i){ for(int j=0; j<v[i].size(); ++j) for(int t=j+1; t<v[i].size(); ++t) if(sum[v[i][t]] - sum[v[i][j]-1]){ ans += v[i].size() - t; break; } } printf("%lld\n", ans); }