2020.07.18模拟4
老姚出题我必糊
话说回来这套题虽然感觉考得不高,但是很有价值,都是那种看完题目有思路,码起来又拿不到满分(还是我tcl),这样的题改起来收获会更大点
A.渔民的烦恼
Descrption
在某个海边小国,大多数居民都是渔民,这个国家的所有城镇都沿直线分布在海边。渔民们捕获大量的海鱼,但就象世界上大多数的渔民一样,他们并不喜欢吃鱼,所以他们决定从邻国收养一些贫困家庭的小孩,让他们来帮着吃鱼,国家规定每个城镇收养的贫困儿童数量必须相等。
一条又长又直的公路贯穿整个海岸将所有的城镇连接了起来,所以每个城镇(除去第一个和最后一个)都直接和相邻的两个城镇相连接。一个小孩一年要吃掉一吨鱼,每个城镇捕获的鱼既可以在本地吃也可以运往其它城市吃,在运输过程中,每公里要上交一吨鱼作为过路费。
已知每个城镇一年的捕鱼产量,并假设运输方案是最佳的,计算最多能收奍多少个贫困儿童。
Input
第一行包含一个整数 N,其中 1≤N≤100,000,表示城镇总数。
接下来的 N行每行包含两个整数 A 和 B,其中 1≤A≤1,000,000,000,0≤B≤1,000,000,000
分别表示城镇的位置(坐标)和该城镇的捕鱼产量,所有城镇按其位置从小到大排序给出,注意问题一定存在正整数解。
Output
输出文件仅一行,包含一个整数表示每个城镇最多能够收养的贫困儿童数量。
Sample Input
4
20 300
40 400
340 700
360 600
Sample Output
415
solution
拿到题目一眼就看出来要二分答案
本来感觉挺简单的,代码也不长,可是码完之后样例没有过
以为问题不大,然后就想简单调一下就过了
于是一个小时过去了,mgl也在调,未果,果断弃掉
等到最后快要考试结束的时候
一不小心调过了,交上去40分
看下之前提交的0分,有点玄
正解
没错就是二分,然而少考虑了情况
只是考虑从别的地方运进来
没有算运出去
能水40还不错。。。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define int long long
using namespace std;
inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
const int maxn = 100010;
int fish[maxn];
int pos[maxn];
int n;
inline bool check(int x){
int tmp = 0;
for(int i = 1; i < n; i++){
int y = tmp + fish[i];
if(y < x)
tmp = y - x - (pos[i + 1] - pos[i]);
else{
tmp = y - x - (pos[i + 1] - pos[i]);
if(tmp < 0)
tmp = 0;
}
}
return fish[n] + tmp >= x;
}
inline int judge(int l, int r){
while(l < r){
int mid = (l + r + 1) >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
signed main(){
n = read();
int maxx = 0;
for(int i = 1; i <= n; i++){
pos[i] = read();
fish[i] = read();
maxx = max(maxx, fish[i]);
}
cout << judge(0, maxx) << endl;
return 0;
}
B.乘车路线
Descrption
编号为 1∼N的 N 座城镇用若干仅供单向行驶的道路相连,每条道路上均有两个参数:道路长度(length)和在该条道路上行驶的费用(cost)。
BOB准备从城镇 1 出发到达城镇 N,但他目前只有 W 的钱,为此,你需要帮助他寻找一条从城镇 1 到城镇 N
在他能支付的前提下的一条最短路线。
Input
W N M
(N为城镇数目,2<=N<=100,M 为道路条数,1<=M<=10000,W 为钱的数目,0<=W<=1000)
随后的 M行每行为一条道路的信息,包含 4 个数值(u,v,w,cost),表示从城镇 u 到 v 有一条长度为 w 的单向道路,经过这条道路需要花费 cost 。(1<=u,v<=N,1<=w<=100,0<=cost<=100)
Output
输出最短长度,若无解,则输出“NO”;
Sample Input
5 6 7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
Sample Output
11
solution
这个……挺玄学的,拿着一个无法证明正确性的算法
可以说是完全不对的算法水到了高达80分
一定是数据太水了,要加强数据迫害下一届
这个不正确的算法是,分别给dis和cost跑SPFA
分别限制然后就卡了80分~
正解
二维SPFA
加一维限制费用
\(dis[i][j]\) 表示\(i\)到源点花费了\(j\)的最短距离。
这个是错解
/*
记得删调试
读入顺序写错了调了20分钟
淦
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
//#define int long long
using namespace std;
inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
const int maxn = 52000;
struct node{
int to, nxt, w, c;
}edge[maxn << 1];
int head[maxn], tot;
inline void add(int u, int v, int w, int c){
edge[++tot].to = v;
edge[tot].nxt = head[u];
edge[tot].w = w;
edge[tot].c = c;
head[u] = tot;
}
int dis[maxn];
bool vis[maxn];
int cost[maxn];
int n, m, k;
inline void spfa1(int x){
queue<int> q;
memset(dis, 0x3f, sizeof dis);
// memset(vis, 0, sizeof vis);
q.push(x);
dis[x] = 0;
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u]; i; i = edge[i].nxt){
int v = edge[i].to;
if(dis[v] > dis[u] + edge[i].w && cost[u] + edge[i].c <= k){
dis[v] = dis[u] + edge[i].w;
cost[v] = cost[u] + edge[i].c;
if(!vis[v])
q.push(v), vis[v] = 1;
}
}
}
}
int dis1[maxn];
int ans[maxn];
inline void spfa2(int x){
queue<int> q1;
memset(cost, 0x3f, sizeof cost);
memset(vis, 0, sizeof vis);
q1.push(x);
cost[x] = 0;
dis1[x] = 0;
while(!q1.empty()){
int u = q1.front();
q1.pop();
vis[u] = 0;
for(int i = head[u]; i; i = edge[i].nxt){
int v = edge[i].to;
if(cost[v] > cost[u] + edge[i].c){
cost[v] = cost[u] + edge[i].c;
dis1[v] = dis1[u] + edge[i].w;
ans[v] = min(dis[v], dis1[v]);
if(!vis[v])
q1.push(v), vis[v] = 1;
}
}
}
}
signed main(){
k = read(), n = read(), m = read();
for(int i = 1; i <= m; i++){
int u = read(), v = read(), w = read(), c = read();
add(u, v, w, c);
}
int minn = 0x7fffffff - 1;
spfa1(1);
spfa2(1);
for(int i = 1; i <= n ;i++)
minn = min(minn, cost[i]);
if(minn > k) return cout << "NO\n", 0;
cout << ans[n] << endl;
return 0;
}
AC代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
const int maxn = 52000;
struct node{
int to, nxt, w, c;
}edge[maxn << 1];
int head[maxn], tot;
inline void add(int u, int v, int w, int c){
edge[++tot].to = v;
edge[tot].nxt = head[u];
edge[tot].w = w;
edge[tot].c = c;
head[u] = tot;
}
int dis[1005][10005];
bool vis[1005][10005];
int cost[maxn];
int n, m, k;
int ans = 0x7fffffff - 1;
inline void spfa(int x){
memset(dis,0x3f,sizeof(dis));
queue<pair<int,int> > q;
dis[x][0] = 0;
q.push(std::make_pair(x,0));
while(!q.empty()){
pair<int,int> t = q.front();
q.pop();
int u = t.first, money = t.second;
vis[u][money] = 0;
for(int i = head[u]; i; i = edge[i].nxt){
int v = edge[i].to, w = edge[i].w, c = edge[i].c, y;
if(money + c > k)continue;
if(dis[v][money + c] > (y = dis[u][money] + w)){
dis[v][money + c] = y;
if(!vis[v][money + c]){
vis[v][money + c] = 1;
q.push(make_pair(v, money + c));
}
}
}
}
int ans = 0x7fffffff - 1;
for(int i = 0; i <= k; ++i)
ans = min(ans, dis[n][i]);
if(ans == 0x7fffffff - 1)
printf("NO\n");
else
printf("%d\n",ans);
}
signed main(){
k = read(), n = read(), m = read();
for(int i = 1; i <= m; i++){
int u = read(), v = read(), w = read(), c = read();
add(u, v, w, c);
}
spfa(1);
return 0;
}
C.Cloakroom
Descrption
有n件物品,每件物品有三个属性 a[i],b[i],ci
q个询问,每个询问由非负整数 m,k,s 组成,问是否能够选出某些物品使得:
对于每个选的物品i,满足 a[i]<=m 且 b[i]>m+s
所有选出物品的c[i]的和正好是 k
Input
第一行一个正整数 n(n<=1,000),接下来 n 行每行三个正整数,分别表示 c[i],a[i],b[i] (c[i]<=1,000,1<=a[i]<b[i]<=109)
下面一行一个正整数 q(q<=1,000,000),接下来 q 行每行三个非负整数 m,k,s(1<=m<=109,1<=k<=100,000,0<=s<=109)
Output
输出q行,每行为 "\(TAK "(yes)或"NIE"(no\)),第 i 行对应第 i 此询问的答案。
Sample Input
5
6 2 7
5 4 9
1 2 4
2 5 8
1 3 9
5
2 7 1
2 7 2
3 2 0
5 7 2
4 1 5
Sample Output
TAK
NIE
TAK
TAK
NIE
solution
考场没的思路,直接就输出其中一个骗了6分???
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e6+50,maxe=1e3+50,INF=0x3f3f3f3f;
inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
int n,q;
struct Node1{
int a,b,c;
inline bool operator < (const Node1 &A)const{
return a<A.a;
}
}a[maxn];
struct Node2{
int m,k,s,ci;
inline bool operator < (const Node2 &A)const{
return m<A.m;
}
}b[maxn];
int f[maxn],ans[maxn];
signed main(){
n = read();
for(int i = 1; i <= n; i++){
a[i].c = read();
a[i].a = read();
a[i].b = read();
}
q = read();
for(int i = 1; i <= q; i++){
b[i].m = read();
b[i].k = read();
b[i].s = read();
b[i].ci = i;
}
sort(a + 1, a + n + 1);
sort(b + 1, b + q + 1);
f[0] = INF;
int j = 1;
for(int i = 1; i <= q; i++){
while(j <= n && a[j].a <= b[i].m){
for(int k = 100000; k >= a[j].c; k--)
f[k] = max(f[k], min(f[k - a[j].c], a[j].b));
j++;
}
if(f[b[i].k] > b[i].m + b[i].s)
ans[b[i].ci] = 1;
}
for(int i = 1; i <= q; i++){
if(ans[i]) cout << "TAK\n";
else cout << "NIE\n";
}
return 0;
}
D.星际网络
Descrption
LY星系有很多个星球。它们之间通过一个巨大的互联网进行通讯。随着信息时代的发展,旧的网络已经不能满足需求
于是 LY星系决定建设一个新的网络。
LY星系有很多个星球,有些星球一天有几十个小时,有些星球一天只有几个小时。但每个星球的一个小时都是一样长的。因此每个星球一天的长短都不一样,这就导致了一个问题:星球上的生物都是在白天工作夜晚 休息,因此每个星球每天都有上网高峰期和低峰期,当很多星球同时达到高峰期时,网络便会变得异常拥堵,进而带来延迟。所以 LY星系需要建设一个有足够大带宽的网络来避免这一问题。现在他们想知道,网络在一个小时内的最大流量是多少。
Input
输入数据的第一行为一个正整数N,表示 LY 星系共有 N个星球。
接下来N行,每行描述一个星球。对于每个星球的描述,开头为两个正整数 D,T,表示这个星球一天有 D 个小时,当前位于 T 时刻(即某一天已经过去了 T
小时).接下来是D个正整数 q0,q1……qD−1,其中 qi 表示第 i 小时到第 i+1小时的流量。
Output
输出共一行,为一个整数 Ans,表示一个小时内的最大流量。
Sample Input
2
4 0 1 2 3 4
2 0 3 1
Sample Output
6
solution
考场直接数组模拟暴力,妥妥爆零
正解
首先观察到算法时间复杂度与n无关,因为一天的长度相同的星球都可以合并,至多24个。
若A,B星球的小时数互质,则 A 星球每个时刻与 B 星球每个时刻均有机会重合。
也就是说,若 A 星球的小时数与 1∼24 其他数都互质,则无论其他数字如何选择,这个星球都可以取到它的最大流量。
13,17,19,23 满足这个条件。其他数字暴力枚举到它们的最小公倍数即可。
#include <bits/stdc++.h>
typedef long long LL;
const int MAX = 55440;
int n,tmp[30];
LL ans,psum,sum[30][30];
void Calc(int D){
LL Max = 0;
for(int i = 1; i <= D; ++i)Max = std::max(Max,sum[D][i]);
psum += Max;
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; ++i){
int D,T;scanf("%d%d",&D,&T);
for(int j = 1; j <= D; ++j)scanf("%d",&tmp[j]);
for(int st = T + 1,t = 1; t <= D; ++st,++t){
if(st > D)st -= D;
sum[D][t] += tmp[st];
}
}
Calc(13);Calc(17);Calc(19);Calc(23);
for(int i = 1; i <= MAX; ++i){
LL cursum = 0;
for(int j = 1; j <= 24; ++j){
if(j == 13 || j == 17 || j == 19 || j == 23)continue;
int cur = (i - 1) % j + 1;
cursum += sum[j][cur];
}
ans = std::max(ans,cursum);
}
printf("%lld\n",ans + psum);
return 0;
}