Problem A.Fraction
签到题,给出一个数n,求a,b使得a+b=n且(a,b)=1(a
Problem B.Maxim Buys an Apartment
签到题,但是有部分细节需要注意。题意:有一排并列的房子,总共有n间,然后当前已经有k间房子被别人住了,现在有个人要搬进去住,这个人喜欢热闹(我不喜欢)他要住一间旁边有人住的房子,问对于k间房已经有人住的情况下,他最少,最多有几间房可以选择。
1<=n<=109,0<=k<=n。
题解:显然k间房放到一边的时候最小,就一间可以选。然后考虑,当K比较小的时候,一间房子可以管左边右边两个房子,k个房子最多管
k∗2
个房子,然后又有k个房子被占,所以总共
k∗3
个房子,比较
k∗3
和n的大小即可,如果小,最多
k∗2
,否则
n−k
个。最后注意k=0的情况和n=k的情况。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<set>
#include<queue>
using namespace std;
long long n, k;
int main()
{
scanf("%lld%lld", &n, &k);
long long minn = 1;
if (n == k || k == 0) minn = 0;
long long maxx = 0;
if (k == 0)
{
maxx = 0;
}
else if (k*3 <= n)
{
maxx = 2 * k;
}
else
{
maxx = n-k;
}
printf("%lld %lld\n", minn, maxx);
return 0;
}
Problem C.Planning
这个题题意大概是调度航班问题,然后有n个航班,一开始第i个航班就是在时间i起飞,k表示延误了现在的时间k,从k时间开始往后航班才能起飞,然后每个单位时间起飞一个航班,每个航班有一个延误的代价
Ci
,然后对于一个调度来说有一个代价
cost=∑(ti−i)∗Ci
,而
ti>=i
,因为显然航班不会提前飞。
题解:此题可以考虑贪心,显然我希望代价大的航班越准时越好,排个序,具体看代码。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<set>
#include<queue>
using namespace std;
const int maxn = 600100;
long long n, k;
struct fight{
long long v;
int id;
int ans;
}c[maxn];
bool p[maxn];
int cmp(fight x, fight y)
{
if (x.v != y.v)
return x.v > y.v;
return x.id < y.id;
}
int cmpid(fight x, fight y)
{
return x.id < y.id;
}
int main()
{
scanf("%lld%lld", &n, &k);
for (int i = 1 ; i <= n; ++i)
{
scanf("%lld", &c[i].v);
c[i].id = i;
}
sort(c+1, c+n+1, cmp);
int po = 1;
for (int i = 1; i <= n; ++i)
{
while (p[po+k]) ++po;
if (c[i].id > po+k && p[c[i].id] == 0)
{
p[c[i].id] = 1;
c[i].ans = c[i].id;
}
else
{
p[po+k] = 1;
c[i].ans = po+k;
po++;
}
}
long long sum = 0;
sort(c+1, c+n+1, cmpid);
for (int i = 1; i <= n; ++i)
sum += (c[i].ans-i)*c[i].v;
printf("%lld\n", sum);
for (int i = 1; i < n; ++i)
printf("%d ", c[i].ans);
printf("%d\n", c[n].ans);
return 0;
}
Problem D.Jury Meeting
哎,比赛的时候看题太慢,最后没时间仔细想清楚题,也没时间写了,感觉自己还需要加快速度吧。其实打完后发现这题也是个傻逼题。题意大概就是告诉你有n+1个城市,编号1-n的每个城市都有个陪审员,要飞到城市0,然后再飞回原来的城市,先给出了
n,m,k
,
n
表示除0城市外有n个城市,
题解:考虑k的范围为1e6,可以考虑枚举t表示他们第一天一起开始工作是哪天,即这n个人是一起飞到了0城市,那么第t天之前的机票我显然都买好,且买最便宜的,这可以确定,预处理维护前缀和即可(同时要判断n个人的机票都买了),而他们走的那天显然就是第t+k+1天,这天之后的那些返程机票我显然也能确定,取最便宜的,即预处理维护后缀和(同理,n个人的机票都要买了)。然后扫一遍取最小就可以啦。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<set>
#include<queue>
using namespace std;
const int maxn = 100100;
int n, m, k, lx, rx, minn;
struct ticket{
long long d, f, t, c;
}v[maxn];
long long pre[maxn*10], suf[maxn*10], prem[maxn], sufm[maxn];
int cmp(ticket x, ticket y)
{
return x.d < y.d;
}
void init()
{
int mark1 = 0, mark2 = 0;
int j = 1;
for (int i = 1; i <= minn; ++i)
{
pre[i] = pre[i-1];
while (i == v[j].d)
if (v[j].f != 0 && j <= m)
{
if (prem[v[j].f] == 0)
{
prem[v[j].f] = v[j].c;
pre[v[j].d] += v[j].c;
++mark1;
if (mark1 == n && lx > i) lx = i;
}
else if (v[j].c < prem[v[j].f])
{
pre[v[j].d] += v[j].c-prem[v[j].f];
prem[v[j].f] = v[j].c;
}
++j;
}
else ++j;
}
j = m;
for (int i = minn; i >= 1; --i)
{
suf[i] = suf[i+1];
while (i == v[j].d)
if (v[j].t != 0 && j > 0)
{
if (sufm[v[j].t] == 0)
{
sufm[v[j].t] = v[j].c;
suf[v[j].d] += v[j].c;
++mark2;
if (mark2 == n && rx < i) rx = i;
}
else if (v[j].c < sufm[v[j].t])
{
suf[v[j].d] += v[j].c-sufm[v[j].t];
sufm[v[j].t] = v[j].c;
}
--j;
}
else --j;
}
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= m; ++i)
{
scanf("%lld%lld%lld%lld", &v[i].d, &v[i].f, &v[i].t, &v[i].c);
if (v[i].d > minn) minn = v[i].d;
}
lx = minn, rx = 1;
sort(v+1, v+m+1, cmp);
init();
long long ans = 1e18;
for (int i = lx; i < rx-k; ++i)
if (pre[i]+suf[i+k+1] < ans) ans = pre[i]+suf[i+k+1];
/*for (int i = 1; i <= minn; ++i)
printf("%d ", pre[i]);
printf("\n");
for (int i = 1; i <= minn; ++i)
printf("%d ", suf[i]);
printf("\n");
printf("%d %d\n", lx,rx);*/
if (rx - lx > k) printf("%lld\n", ans);
else printf("-1\n");
return 0;
}