【11/2】模拟赛
第一题 中位数
【题目描述】
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。
【输入格式】
第一行为两个正整数n和b,第二行为1~n的排列。
【输出格式】
输出一个整数,即中位数为b的连续子序列个数。
【样例输入】
| 样例输入1 | 样例输入2 | 样例输入3 |
| 5 4 1 2 3 4 5 |
6 3 1 2 4 5 6 3 |
7 4 5 7 2 4 3 1 6 |
【样例输出】
| 样例输出1 | 样例输出2 | 样例输出3 |
| 2 | 1 | 4 |
【数据范围】
n<=100000。
【分析】
假设b左面有x1个比b大,y1个比b小。b右面有x2个比b打,y2个比b小。那么有x1 + x2 = y1 + y2。移项有,x1 – y1 = – (x2 – y2)。我们先统计b左面每个位置计算出的每个x - y的差值各出现了多少次,然后统计b右面的每个位置计算出的-(x – y)的差值各出现了多少次。由乘法原理将对应的相乘。
第二题 打砖块
【题目描述】
在一个凹槽中放置n层砖块,最上面的一层有n块砖,从上到下每层依次减少一块砖,每块砖都有一个分值,敲掉这块砖就能得到相应的分值,如下图所示。

如果你要敲掉第i层的第j块砖的话,若i=1,你可以直接敲掉它;若i>1,则你必须先敲掉i-1层的第j和第j+1快砖。
你现在可以敲掉最多m块砖,求得分最多能有多少。
【输入格式】
输入文件的第一行为两个正整数n和m;接下来n行,描述这n层砖块上的分值a[i][j],满足0≤a[i][j] ≤100.
【输出格式】
输出文件仅一行为一个正整数,表示被敲掉砖块的最大价值总和。
【样例输入】
4 5
2 2 3 4
8 2 7
2 3
49
【样例输出】
19
【数据范围】
对于20%的数据,满足1≤n≤10,1≤m≤30;
对于100%的数据,满足1≤n≤50,1≤m≤500。
【分析】
首先按照正常的思想,我们会想到以行划分阶段。但是他是有后效性的。于是我们尝试用列划分阶段。

对于上图橘黄色的点。如果取了他,那么粉色的点都会被取走。设f[i][j][k]表示当前是第i列,共取走j个,其中k个在第i列。f[i][j][k] = max(f[i – 1][j – k][p]) + s[i][k]。其中k – 1 <= p < i(即图中有棕色点的范围),s[i][k]表示第i列最上面k个数的和。
结果为所有f[i][m][k]中最大的。
第三题 序列合并
【题目描述】
有两个长度为N的序列A和B,在A和B中各任取一个数相加可以得到N^2个和,求这N^2个和中最小的N个。
【输入格式】
第一行输入一个正整数N;第二行N个整数Ai 且Ai≤10^9;第三行N个整数Bi,且Bi≤10^9。
【输出格式】
输出仅一行,包含n个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。
【样例输入】
5
1 3 2 4 5
6 3 4 1 7
【样例输出】
2 3 4 4 5
【分析】
首先将两个数列排序。第一步固定b中选的数是b[1],和a中所有的数相加,得出n个数,放入小根堆中。
每次从中取出最小的。将他所选的b[i]下表加1,即变成b[i + 1]。然后放回堆中。
第四题 最小密度路径
【题目描述】
给出了一张有N个点M条边的加权有向无环图,接下来有Q个询问,每个询问包括2个结点X和Y,要求算出从X到Y的一条路径,使得密度最小(密度的定义为,路径上边的权值和除以边的数量)
【输入格式】
第一行包括2个整数N和M。
第2到第M+1行,每行三个数字A、B、W,表示从A到B有一条权值为W的有向边。
第M+2行只有一个整数Q。
接下来的Q行,每行有两个整数X和Y,表示一个询问。
【输出格式】
对于每个询问输出一行,表示该询问的最小密度路径的密度(保留3位小数),如果不存在从X到Y的一条路径,则输出“OMG!”
【样例输入】
3 3
1 3 5
2 1 6
2 3 6
2
1 3
2 3
【样例输入】
5.000
5.500
【数据范围】
对于60%的数据,有1≤N≤10;1≤M≤100,1≤W≤1000,1≤Q≤1000;
对于100%的数据,有1≤N≤50;1≤M≤1000,1≤W≤100000,1≤Q≤100000。
【分析】
f[i][j][k]表示从i到j走k条边做能达到的最小值。然后floyd求解。o(n^4)。
给出的数据有误,存在环。
代码
第一题
#include <stdio.h>
#define MAXN 100010
#define pz 150000
int n,b;
int a[MAXN],f[3 * MAXN],g[3 * MAXN];
int main() {
freopen("median.in","r",stdin);
freopen("median.out","w",stdout);
scanf("%d%d",&n,&b);
for (int i = 1;i <= n;++i)
scanf("%d",&a[i]);
int wh,sum,ans;
for (int i = 1;i <= n;++i)
if (a[i] == b) {
wh = i;
break;
}
sum = 0;
++g[pz];
++f[pz];
for (int i = wh - 1;i >0;--i) {
if (a[i] > b)
++sum;
else
--sum;
++f[sum + pz];
}
sum = 0;
for (int i = wh + 1;i <= n;++i) {
if (a[i] < b)
++sum;
else
--sum;
++g[sum + pz];
}
ans = 0;
for (int i = -n;i <= n;++i)
ans += f[i + pz] * g[i + pz];
printf("%d\n",ans);
return 0;
}
第二题
#include <stdio.h>
#include <string.h>
#include <iostream>
#define MAXN 60
#define MAXM 510
using namespace std;
int f[MAXN][MAXM][MAXM],a[MAXN][MAXN],s[MAXN][MAXN];
int n,m,ans;
int main() {
freopen("brike.in","r",stdin);
freopen("brike.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i = 1;i <= n;++i)
for (int j = 1;j <= n - i + 1;++j)
scanf("%d",&a[i][j]);
for (int i = 1;i <= n;++i)
for (int j = 1;j <= i;++j)
s[i][j] = s[i][j - 1] + a[j][n - i + 1];
memset(f,255,sizeof(f));
for (int i = 0;i <= n;++i)
f[i][0][0] = 0;
for (int i = 1;i <= n;++i)
f[i][1][1] = a[1][n - i + 1];
for (int i = 1;i <= n;++i)
for (int k = 0;k <= i;++k)
for (int j = k;j <= m;++j)
for (int p = k - 1;p < i;++p)
if ((p >= 0) && (f[i - 1][j - k][p] != -1)) {
f[i][j][k] = max(f[i][j][k],f[i - 1][j - k][p] + s[i][k]);
if ((j == m) && (f[i][j][k] > ans))
ans = f[i][j][k];
}
printf("%d\n",ans);
return 0;
}
第三题
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MAXN 100010
using namespace std;
struct ss {
int pa,pb,t;
} h[MAXN];
int tot,n,ans;
int a[MAXN],b[MAXN];
int cmp(const void *a,const void *b) {
int c = *(int *)a,d = *(int *)b;
return c - d;
}
void down(int x ) {
int p,q;
p = x;
q = x * 2;
while (q <= tot) {
if ((q + 1 <= tot) && (h[q + 1].t < h[q].t))
++q;
if (h[q].t > h[p].t)
return;
swap(h[q],h[p]);
p = q;
q = p * 2;
}
}
int main() {
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
scanf("%d",&n);
for (int i = 1;i <= n;++i)
scanf("%d",&a[i]);
for (int j = 1;j <= n;++j)
scanf("%d",&b[j]);
qsort(a + 1,n,sizeof(int),cmp);
qsort(b + 1,n,sizeof(int),cmp);
for (int i = 1;i <= n;++i) {
h[i].pa = i;
h[i].pb = 1;
h[i].t = a[i] + b[1];
}
tot = n;
for (int i = tot;i > 0;--i)
down(i);
for (int i = 1;i <= n;++i) {
ans = h[1].t;
printf("%d ",ans);
++h[1].pb;
h[1].t = a[h[1].pa] + b[h[1].pb];
down(1);
}
return 0;
}
第四题
#include <stdio.h>
#define MAXINT 10000010
int n,m,x,y,z,tot;
double f[51][51][501],dis[51][51];
int main() {
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i = 1;i <= n;++i)
for (int j = 1;j <= n;++j)
for (int k = 0;k <= n;++k)
f[i][j][k] = MAXINT;
for (int i = 1;i <= m;++i) {
scanf("%d%d%d",&x,&y,&z);
if (z < f[x][y][1])
f[x][y][1] = z;
}
for (int p = 2;p <= n;++p)
for (int k = 1;k <= n;++k)
for (int i = 1;i <= n;++i)
for (int j = 1;j <= n;++j)
if (f[i][k][p - 1] + f[k][j][1] < f[i][j][p])
f[i][j][p] = f[i][k][p - 1] +f[k][j][1];
scanf("%d",&tot);
for (int i = 1;i <= n;++i)
for (int j = 1;j <= n;++j)
dis[i][j] = MAXINT;
for (int i = 1;i <= n;++i)
for (int j = 1;j <= n;++j)
for (int k = 1;k <= n;++k)
if (f[i][j][k] < MAXINT)
if (f[i][j][k] / k < dis[i][j])
dis[i][j] = f[i][j][k] / k;
for (int i = 1;i <= tot;++i) {
scanf("%d%d",&x,&y);
if (dis[x][y] < MAXINT)
printf("%.3lf\n",dis[x][y]);
else
printf("OMG!\n");
}
return 0;
}
后记
今天的题目写的很悲剧。因为身体感觉很差吧。放假调整一下,下午去买点感冒药。太冷了。
第二题打出了数组观察结果交题的时候忘记删掉了。第四题没有判断动归数组是否有解就直接去计算dis。两百分消失。
浙公网安备 33010602011771号