A. Heist
商店里的键盘都是从某个数开始连续编号的,有一些键盘被盗了,现在给你剩下的键盘编号,求最少被盗了多少个键盘
排个序检查一下就好了。。。
#include
#include
#include
#include
#include
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
int n,a[MAXN],ans;
int main() {
scanf("%d", &n);
for(int i=1; i<=n; i++) {
scanf("%d", &a[i]);
}
sort(a+1, a+n+1);
int sta = a[1];
for(int i=1; i<=n; i++) {
while(sta++ < a[i]) {
ans++;
}
}
printf("%d", ans);
return 0;
}
B. Buying a TV Set
求w<=a, h<=b 且w/h = x/y 的正整数对(w, h)的个数
枚举可以过n^2,怎么优化。。。
可以发现满足要求的w/h 等于 k * (x/y)
也就是说(w, h) = (kx, ky)
有坑点!!! 先把x/y化为最简分数(样例真良心,包含了这种情况)
#include
#include
#include
#include
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
typedef long long ll;
ll n,a,b,x,y;
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a%b);
}
int main() {
cin >> a >> b >> x >> y;
ll temp = gcd(x, y);
x /= temp, y /= temp;
ll q1 = a/x, q2 = b/y;
ll fin = min(q1, q2);
cout << fin;
return 0;
}
C. Coffee Break
Monocarp需要在给定时刻( a1 a 1 ~ an a n )喝点咖啡休息1分钟,每天时间长度为m(这个条件没啥用,因为若 ai>m a i > m 则Monocarp永远喝不到那杯咖啡,输入也保证了 ai≤m a i ≤ m ),然而Monocarp的老板说他必须在两次喝咖啡之间隔开d分钟(假设d = 3,1min时喝了咖啡,则必须5min时才能再喝咖啡,中间隔了2,3,4三分钟)所以他得分好多天喝完给定时刻的咖啡。现在问最少花费天数以及方案(输出一个任意方案即可)
本来排序乱模拟了一遍。。。后来发现用set就能解决这个问题
把ai的值和次序搞一个pair放到set,因为set中的元素都是有序的,所以每次都找begin的元素作为一天的开始,然后在set里不断二分找接下来相隔d分钟的下一个休息时间,注意找到了就删掉。。。
pair默认优先比较first元素再比较second,所以下面的lower_bound的第二个参数为0是最好的,这样任何元素的第二键值都会大于新造的pair
#include
#include
#include
#include
#include
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 200000 + 10;
typedef long long ll;
int n,m,d,ans[MAXN],tot,a[MAXN];
setint , int> > s;
int main() {
scanf("%d%d%d", &n, &m, &d);
for(int i=1; i<=n; i++) {
scanf("%d", &a[i]);
s.insert(make_pair(a[i], i));
}
while(!s.empty()) {
tot++;
int pos = s.begin()->second;
ans[pos] = tot;
s.erase(s.begin());
while(1) {
setint , int> > :: iterator it = s.lower_bound(make_pair(a[pos]+d+1, 0));
if(it == s.end()) break;
pos = it->second;
ans[pos] = tot;
s.erase(it);
}
}
printf("%d\n", tot);
for(int i=1; i<=n; i++) {
printf("%d ", ans[i]);
}
return 0;
}
D. Glider
给定挂载滑翔机的初始高度,滑翔机可以从任意位置(横坐标)跳下,有一些互不相交上升气流区间(按升序给出),滑翔机在这些区间内滑行不会下降,其他区间内每在x轴跑一个单位长度,y轴随之下降一个单位长度,当滑翔机高度为0时,不能通过上升气流再滑动
求滑翔机最多能滑多远(投影到x轴上的位移)
最后答案一定是某些区间的长度之和加上给的h,把区间缩成点,点权是区间长度,预处理出两个区间之间的距离,当成边连着区间,一个朴素的想法是枚举起点,一直往右走,统计一下答案
但是考虑到这样会重复走很多已经走过的路径,考虑到起点是连续的,上一次走过的路径这次应该能用上一部分,维护一下就好了。具体来说就是设一个剩下的“长度”rem(rem一开始为h),当起点从i到i+1时,rem加上从i到i+1的花费,然后再试试用rem能否走到以i为起点走到的最右边,再往右的一些点(保留上次最后的位置),同时注意维护sum,既然不以i为起点,i的点权的贡献也要消去
#include
#include
#include
#include
#include
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 200000 + 10;
typedef long long ll;
int n,m,last[MAXN],ans,rem,h,nxt[MAXN],val[MAXN];
struct segment{
int l, r;
}seg[MAXN];
int main() {
scanf("%d%d", &n, &h);
for(int i=1; i<=n; i++) {
scanf("%d%d", &seg[i].l, &seg[i].r);
val[i] = seg[i].r - seg[i].l;
}
for(int i=2; i<=n; i++) {
int sta = seg[i-1].r, ed = seg[i].l;
int w = ed - sta;
nxt[i-1] = w;
}
rem = h;
int pos = 1;
int sum = val[1];
for(int i=1; i<=n; i++) {
while(1) {
if(rem - nxt[pos] <= 0 || pos > n) break;
rem -= nxt[pos];
pos++;
sum += val[pos];
}
rem += nxt[i];
ans = max(ans, sum + h);
sum -= val[i];
}
printf("%d\n", ans);
return 0;
}