牛客多校第五场题解
Away from College
https://ac.nowcoder.com/acm/contest/11256/A
B - Boxes
solved by Tryna.(-)
题意: 给出若干个盒子,盒子里面只有一个球,颜色为黑或白,每拆开一个盒子有一个花费,还可以通过花费一次来知道盒子内总共有多少黑球,求知道所有盒子中是什么球的花费的最小期望
题解:
- 不询问,所有盒子都开一遍,花费为
- 询问一遍,按花费从大到小开盒子,开到第
个盒子能直接判定的前提是后面全部同色并且第
个盒子与后面异色,所以一共需要
个球为
或者
,这两种情况出现的概率都为
,相加后为
,排序后处理一下前缀和即可
#include<bits/stdc++.h>
using namespace std;
#define dbg(x...) do { cout << #x << " -> "; err(x); } while (0)
void err () { cout << endl;}
template <class T, class... Ts>
void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...);}
#define ll long long
#define ull unsigned long long
#define LL __int128
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int>
#define PII pair<ll, ll>
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define em emplace
#define mp(a,b) make_pair(a,b)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define PAUSE system("pause");
const double Pi = acos(-1.0);
const double eps = 1e-10;
const int maxn = 1e5 + 10;
const int maxm = 6e2 + 10;
const int mod = 998244353;
// const int P = 131;
const int S = 5;
inline ll rd() {
ll f = 0; ll x = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
if (f) x = -x;
return x;
}
void out(ll a) {if(a<0)putchar('-'),a=-a;if(a>=10)out(a/10);putchar(a%10+'0');}
#define pt(x) out(x),puts("")
inline void swap(ll &a, ll &b){ll t = a; a = b; b = t;}
inline void swap(int &a, int &b){int t = a; a = b; b = t;}
inline ll min(ll a, ll b){return a < b ? a : b;}
inline ll max(ll a, ll b){return a > b ? a : b;}
ll qpow(ll n,ll k,ll mod) {ll ans=1;while(k){if(k&1)ans=ans*n%mod;n=n*n%mod;k>>=1;}return ans%mod;}
int n;
double c, a[maxn], sum[maxn];
void solve(){
scanf("%d %lf", &n, &c);
for(int i = 1; i <= n; i++) {
scanf("%lf", &a[i]);
}
sort(a + 1, a + 1 + n);
for(int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + a[i];
double minn = sum[n];
double base = 0.5;
double ans = c;
for(int i = n - 1; i >= 1; i--) {
ans += base * sum[i];
base *= 0.5;
}
printf("%.6f\n", min(ans, minn));
}
int main() {
// freopen("in.txt","r",stdin);
// freopen("out.txt", "w", stdout);
int t = 1;
// t = rd();
// scanf("%d", &t);
// cin >> t;
while(t--)
solve();
PAUSE;
return 0;
} D - Double Strings
题意:
从、
两个串中各选取两个相同大小的子集(就算字母相同,只要选取的位置不同,就算作不一样的),要求存在一个位置
,使得前面的字母都相同,并且第
位上从
选取的字母要小于
中选取的。问这样的子集有多少对。
思路:
很明显的题,我们需要做的是,当选取一对
,
时,若
,我就要计算出
,
之前能凑出多少个相等的字符串,之后能凑出多少个长度相同的字符串。
第一部分的和最长公共子序列很像。我可以用
去匹配
,用
去匹配
。因为是求数量,这里把取
改成相加。但是这样重复计算了既不用第
位,也不用第
位的情况,所以要减去
。如果
,我就能让它俩匹配,又能将
的情况加上去了。
第二部分,我们设,
,且
可以马上列出一个排列组合的式子
。
可以转换成
。我们带回原式子,发现是每次在
里选
个,b里选
个,这个总和就相当于在
里选
个。所以我们只需要计算
了。
比较大,组合数可以预处理一下,降个
的复杂度,不过加上去也能刚好卡过去。
#include <bits/stdc++.h>
using namespace std;
inline int rd() {
int f = 0; int x = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
if (f) x = -x;
return x;
}
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 5e3 + 7;
const ll mod = 1e9 + 7;
ll powmod(ll a, ll b) {
ll res = 1;
for (; b; b >>= 1) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
}
return res;
}
ll inv[N << 1], fac[N << 1];
ll C(int n, int m) {
assert(n >= 0 && m >= 0);
assert(n >= m);
return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
char a[N], b[N];
ll dp[N][N];
void solve() {
scanf("%s", a + 1);
scanf("%s", b + 1);
int lena = strlen(a + 1), lenb = strlen(b + 1);
assert(lena < N - 1 && lenb < N - 1);
ll ans = 0;
for (int i = 0; i < N; ++i) {
dp[i][0] = dp[0][i] = 1;
}
for (int i = 1; i <= lena; ++i) {
for (int j = 1; j <= lenb; ++j) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];
dp[i][j] %= mod;
if (a[i] == b[j]) dp[i][j] += dp[i - 1][j - 1];
dp[i][j] += mod;
dp[i][j] %= mod;
if (a[i] < b[j]) {
ans += dp[i - 1][j - 1] * C(lena - i + lenb - j, lena - i) % mod;
ans %= mod;
}
}
}
printf("%lld\n", ans);
}
int main() {
fac[0] = fac[1] = 1;
for (int i = 2; i < N * 2; ++i) {
fac[i] = fac[i - 1] * (ll)i % mod;
}
inv[0] = 1;
for (int i = 1; i < N * 2; ++i) {
inv[i] = powmod(fac[i], mod - 2);
}
int t = 1;
while (t--) solve();
return 0;
} F - Finding Points
题意: 给出一个凸包的顶点集,要求在凸包内找一点,令
为
中的最小值,求
的最大值
题解: 一种很明显的思路就是三分套三分,分别枚举坐标和
坐标,然后枚举
坐标的时候我认为需要确定在当前
值的情况下
的范围,不知道为啥很多码不用判断这个也能过,还是说这么枚举点一定在凸包内部
#include<bits/stdc++.h>
using namespace std;
#define dbg(x...) do { cout << #x << " -> "; err(x); } while (0)
void err () { cout << endl;}
template <class T, class... Ts>
void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...);}
#define ll long long
#define ull unsigned long long
#define LL __int128
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int>
#define PII pair<ll, ll>
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define em emplace
#define mp(a,b) make_pair(a,b)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define PAUSE system("pause");
const double Pi = acos(-1.0);
const double eps = 1e-10;
const int maxn = 1e2 + 10;
const int maxm = 6e2 + 10;
const int mod = 998244353;
const int S = 5;
inline ll rd() {
ll f = 0; ll x = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
if (f) x = -x;
return x;
}
void out(ll a) {if(a<0)putchar('-'),a=-a;if(a>=10)out(a/10);putchar(a%10+'0');}
#define pt(x) out(x),puts("")
inline void swap(ll &a, ll &b){ll t = a; a = b; b = t;}
inline void swap(int &a, int &b){int t = a; a = b; b = t;}
inline ll min(ll a, ll b){return a < b ? a : b;}
inline ll max(ll a, ll b){return a > b ? a : b;}
ll qpow(ll n,ll k,ll mod) {ll ans=1;while(k){if(k&1)ans=ans*n%mod;n=n*n%mod;k>>=1;}return ans%mod;}
int sgn(double x){
if(fabs(x) < eps) return 0;
else return x < 0?-1:1;
}
struct Point{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
Point operator + (Point B){return Point(x + B.x,y + B.y);}
Point operator - (Point B){return Point(x - B.x,y - B.y);}
Point operator * (double k){return Point(x*k,y*k);}
Point operator / (double k){return Point(x/k,y/k);}
bool operator == (Point B){return sgn(x - B.x) == 0 && sgn(y - B.y) == 0;}
bool operator < (const Point &b)const{
if(x == b.x) return y < b.y;
return x < b.x;
}
}P[maxn];
struct Line{
Point p1,p2;
Line(){};
Line(Point p1,Point p2):p1(p1),p2(p2){}
}L[maxn];
double Dot(Point A, Point B){return A.x*B.x + A.y*B.y;}
double Cross(Point A, Point B){return A.x*B.y - A.y*B.x;}
bool Point_on_seg(Point p, Line v){ //0为不在线段上,1为在线段上
return sgn(Cross(p - v.p1, v.p2 - v.p1)) == 0 &&
sgn(Dot(p - v.p1, p - v.p2)) <=0;
}
bool Cross_segment1(Point a, Point b, Point c, Point d){
//两线段是否非规范相交
if(a == c || a == d) return 0;
if(b == c || b == d) return 0;
return
max(a.x, b.x) >= min(c.x, d.x)&&
max(c.x, d.x) >= min(a.x, b.x)&&
max(a.y, b.y) >= min(c.y, d.y)&&
max(c.y, d.y) >= min(a.y, b.y)&&
sgn(Cross(b - a, c - a)) * sgn(Cross(b - a, d - a)) <= 0&&
sgn(Cross(d - c, a - c)) * sgn(Cross(d - c, b - c)) <= 0;
}
Point Cross_point(Point a, Point b, Point c, Point d){
double s1 = Cross(b - a, c - a);
double s2 = Cross(b - a, d - a);
return Point(c.x * s2 - d.x * s1, c.y * s2 - d.y * s1) / (s2 - s1);
}
int Point_in_polygon(Point pt, Point *p, int n){ //判断点和多边形的位置关系
for(int i = 0; i < n; i++){
if(p[i] == pt) return 3; //点在多边形的顶点上
}
for(int i = 0; i < n; i++){
Line v = Line(p[i], p[(i + 1) % n]);
if(Point_on_seg(pt, v)) return 2; //点在多边形边上
}
int num = 0;
for(int i = 0; i < n; i++){
int j = (i + 1) % n;
int c = sgn(Cross(pt - p[j], p[i] - p[j]));
int u = sgn(p[i].y - pt.y);
int v = sgn(p[j].y - pt.y);
if(c > 0 && u < 0 && v >= 0) num++;
if(c < 0 && u >= 0 && v < 0) num--;
}
return num != 0; //1点在内部; 0点在外部
}
int n;
double getangle(double X1, double Y1, double X2, double Y2, double X3, double Y3) {
double theta = atan2(X1 - X3, Y1 - Y3) - atan2(X2 - X3, Y2 - Y3);
if(theta > Pi)
theta -= Pi * 2;
if (theta < -Pi)
theta += Pi * 2;
theta = abs(theta * 180.0 / Pi);
return theta;
}
double cal(double x, double y) {
double minn = 180.0;
for(int i = 0; i < n; i++) {
int id = (i + 1) % n;
double angle = getangle(P[i].x, P[i].y, P[id].x, P[id].y, x, y);
minn = min(minn, angle);
}
return minn;
}
double ly, ry, L1, R;
double f(double x) {
Line l = Line({x, 10000}, {x, -10000});
double ly = INF, ry = -INF;
for(int i = 0; i < n; i++) {
if(Cross_segment1(l.p1, l.p2, L[i].p1, L[i].p2) != 1) continue;
Point tmp = Cross_point(l.p1, l.p2, L[i].p1, L[i].p2);
ly = min(ly, tmp.y);
ry = max(ry, tmp.y);
}
double midl, midr;
L1 = ly, R = ry;
while(R - L1 > eps) {
midl = L1 + (R - L1) / 3.0;
midr = R - (R - L1) / 3.0;
if(cal(x, midl) > cal(x, midr)) R = midr;
else L1 = midl;
}
return cal(x, L1);
}
void solve(){
scanf("%d", &n);
double lx = inf, rx = -inf;
ly = inf, ry = -inf;
for(int i = 0; i < n; i++) {
scanf("%lf %lf", &P[i].x, &P[i].y);
lx = min(lx, P[i].x);
rx = max(rx, P[i].x);
ly = min(ly, P[i].y);
ry = max(ry, P[i].y);
}
for(int i = 0; i < n; i++) {
L[i] = Line(P[i], P[(i + 1) % n]);
}
double midl, midr;
while(rx - lx > eps){
midl = lx + (rx - lx)/ 3.0;
midr = rx - (rx - lx)/ 3.0;
if(f(midl) > f(midr)) rx = midr;
else lx = midl;
}
printf("%.14f\n", f(lx));
}
int main() {
// freopen("in.txt","r",stdin);
// freopen("out.txt", "w", stdout);
int t = 1;
// t = rd();
// scanf("%d", &t);
// cin >> t;
while(t--)
solve();
return 0;
} 题解: 用三分套三分能过那么用模拟退火肯定也能过。但我的模拟退火似乎不是很优秀,在小样例并且点与点之间的距离较远时误差会较大,测试了一下平均六发过一次,可能算欧了。
#include<bits/stdc++.h>
using namespace std;
#define dbg(x...) do { cout << #x << " -> "; err(x); } while (0)
void err () { cout << endl;}
template <class T, class... Ts>
void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...);}
#define ll long long
#define ull unsigned long long
#define LL __int128
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int>
#define PII pair<ll, ll>
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define em emplace
#define mp(a,b) make_pair(a,b)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define PAUSE system("pause");
const double Pi = acos(-1.0);
const double eps = 1e-10;
const int maxn = 1e2 + 10;
const int maxm = 6e2 + 10;
const int mod = 998244353;
const double startT = 100000;
const int S = 5;
const int dx[]= {-1,-1,-1,0,0,1,1,1};
const int dy[]= {-1,0,1,-1,1,-1,0,1};
inline ll rd() {
ll f = 0; ll x = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
if (f) x = -x;
return x;
}
void out(ll a) {if(a<0)putchar('-'),a=-a;if(a>=10)out(a/10);putchar(a%10+'0');}
#define pt(x) out(x),puts("")
inline void swap(ll &a, ll &b){ll t = a; a = b; b = t;}
inline void swap(int &a, int &b){int t = a; a = b; b = t;}
inline ll min(ll a, ll b){return a < b ? a : b;}
inline ll max(ll a, ll b){return a > b ? a : b;}
ll qpow(ll n,ll k,ll mod) {ll ans=1;while(k){if(k&1)ans=ans*n%mod;n=n*n%mod;k>>=1;}return ans%mod;}
int sgn(double x){
if(fabs(x) < eps) return 0;
else return x < 0?-1:1;
}
struct Point{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
Point operator + (Point B){return Point(x + B.x,y + B.y);}
Point operator - (Point B){return Point(x - B.x,y - B.y);}
Point operator * (double k){return Point(x*k,y*k);}
Point operator / (double k){return Point(x/k,y/k);}
bool operator == (Point B){return sgn(x - B.x) == 0 && sgn(y - B.y) == 0;}
bool operator < (const Point &b)const{
if(x == b.x) return y < b.y;
return x < b.x;
}
}P[maxn];
int n;
double getangle(double X1, double Y1, double X2, double Y2, double X3, double Y3) {
double theta = atan2(X1 - X3, Y1 - Y3) - atan2(X2 - X3, Y2 - Y3);
if(theta > Pi)
theta -= Pi * 2;
if (theta < -Pi)
theta += Pi * 2;
theta = abs(theta * 180.0 / Pi);
return theta;
}
double cal(double x, double y) {
double minn = 180.0;
for(int i = 0; i < n; i++) {
int id = (i + 1) % n;
double angle = getangle(P[i].x, P[i].y, P[id].x, P[id].y, x, y);
minn = min(minn, angle);
}
return minn;
}
void solve(){
scanf("%d", &n);
double maxx = -inf, minn = inf;
for(int i = 0; i < n; i++) {
scanf("%lf %lf", &P[i].x, &P[i].y);
maxx = max(maxx, max(P[i].x, P[i].y));
minn = min(minn, min(P[i].x, P[i].y));
}
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int times = 5;
double bas = maxx - minn + 1;
if(n <= 4)
times = 80;
else if(n <= 5)
times = 70;
else if(n <= 10) {
times = 25;
}
else if(n <= 20) times = 10;
double T = startT, delta = 0.985, x, y;
double ans = -inf;
x = 0, y = 0;
double base = 0.02 / times;
while(times--) {
T = startT, delta = 0.980 + times * base - 0.001;
while(T > eps) {
int a = rng() % 2;
int b = rng() % (int)startT;
double next_x, next_y;
if(a == 0)
next_x = x + b * T;
else next_x = x - b * T;
a = rng() % 2, b = rng() % (int)startT;
if(a == 0)
next_y = y + b * T;
else next_y = y - b * T;
if(cal(x, y) < cal(next_x, next_y)) {
x = next_x;
y = next_y;
}
ans = max(ans, cal(x, y));
T *= delta;
}
// x = 0, y = 0;
T = startT, delta = 0.98 + times * base - 0.001;
while(T > eps) {
int a = rng() % 2;
int b = rng() % 500;
double next_x, next_y;
if(a == 0)
next_x = x + b * T;
else next_x = x - b * T;
a = rng() % 2, b = rng() % 500;
if(a == 0)
next_y = y + b * T;
else next_y = y - b * T;
if(cal(x, y) < cal(next_x, next_y)) {
x = next_x;
y = next_y;
}
ans = max(ans, cal(x, y));
T *= delta;
}
}
// printf("%.5lf %.5lf\n", x, y);
printf("%.14lf\n", ans);
}
int main() {
// freopen("in.txt","r",stdin);
// freopen("out.txt", "w", stdout);
int t = 1;
// cin >> t;
while(t--)
solve();
return 0;
} H - Holding Two
题意: 构造一个的
矩阵,满足没有三个连续(行、列、斜线)的元素相同
题解:
这样构造即可
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define dbg(x...) do { cerr << "\033[32;1m" << #x << " -> "; err(x);} while(0)
void err() { cerr << "\033[39;0m" << endl;}
template<class T, class... Ts> void err(const T& arg, const Ts&... args) { cerr << arg << " "; err(args...);}
typedef long long ll;
const int maxn = 1e3 + 7;
int n, m, a[maxn][maxn];
void run() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
int tmp = 1;
if(i % 2 == 0) tmp = 0;
for(int j = 1; j <= m; j += 2) {
a[i][j] = a[i][j + 1] = tmp;
tmp = 1 - tmp;
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
printf("%d", a[i][j]);
}
puts("");
}
}
int main() {
int t = 1;
// scanf("%d", &t);
while (t--) run();
return 0;
} J - Jewels
题意:
三维坐标,人在,每整数秒可以选择一个宝石,花费为宝石到人的距离的平方,在第
秒时宝石
的的坐标为
,问最小花费。
思路:,
不会变化,直接算入答案。
都为正,答案只会越来越大,所以每秒都要取一个,就转换成了
模型。
费用流麻了,拉了份
行的
板子才能过。
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define dbg(x...) do { cerr << "\033[32;1m" << #x << " -> "; err(x);} while(0)
void err() { cerr << "\033[39;0m" << endl;}
template<class T, class... Ts> void err(const T& arg, const Ts&... args) { cerr << arg << " "; err(args...);}
typedef long long ll;
const int N = 3e2 + 7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll cap[N][N];
ll slack[N], wx[N], wy[N];
int n, m, k, tot;
int match[N], pre[N], used[N], vis[N];
void bfs(int u) {
ll px, py = 0, yy = 0, d;
memset(pre, 0, sizeof(pre));
memset(slack, 0x3f, sizeof(slack));
used[py] = u;
while (used[py]) {
px = used[py] ,d = INF, vis[py] = 1;
for (int i = 1; i <= tot; ++i) {
if (!vis[i]) {
if (slack[i] > wx[px] + wy[i] - cap[px][i]) {
slack[i] = wx[px] + wy[i] - cap[px][i], pre[i] = py;
}
if (slack[i] < d) d = slack[i], yy = i;
}
}
for (int i = 0; i <= tot; ++i) {
if (vis[i]) wx[used[i]] -= d, wy[i] += d;
else slack[i] -= d;
}
py = yy;
}
while (py) used[py] = used[pre[py]], py = pre[py];
}
ll km() {
memset(wx, 0, sizeof(wx));
memset(wy, 0, sizeof(wy));
memset(used, 0, sizeof(used));
for (int i = 1; i <= tot; ++i) {
memset(vis, 0, sizeof(vis));
bfs(i);
}
ll ans = 0;
for (int i = 1; i <= tot; ++i) {
ans += cap[used[i]][i], match[used[i]] = i;
}
return ans;
}
void run() {
scanf("%d", &n);
ll ans = 0;
tot = n;
for (int i = 1; i <= n; ++i) {
ll x, y, z, v;
scanf("%lld %lld %lld %lld", &x, &y, &z, &v);
ans += x * x;
ans += y * y;
for (int j = 1; j <= n; ++j) {
cap[j][i] = -((ll)(j - 1) * v + z) * ((ll)(j - 1) * v + z);
}
}
ans += -km();
printf("%lld\n", ans);
}
int main() {
int t = 1;
while (t--) run();
return 0;
}
K - King of Range
题意:
给定序列,求多有少对不同的数对(
,
),使得区间内的最大值和最小值的差值大于
。
思路:
假设我们从出发,一路向右走,走到
时刚好满足条件,那么
~
都是满足要求的。这时候把l向右移动一位,能正好满足它的
肯定会大于等于先前求得的
,符合决策单调性。所以用个双指针,区间求最大最小值就行了。
序列是给定的,但是有多组询问,带个一直跑很容易
。所以上
就能实现
求区间最大最小值了。
之前骂RMQ没用有多狠,现在就有多惨
#include <bits/stdc++.h>
using namespace std;
inline int rd() {
int f = 0; int x = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
if (f) x = -x;
return x;
}
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 7;
int n, m, k;
int mx[N][20], mn[N][20];
void st(int n){
for(int l=1;(1<<l)<=n;l++){
for(int i=1;i+(1<<l)-1<=n;i++){
mx[i][l]=max(mx[i][l-1],mx[i+(1<<(l-1))][l-1]);
mn[i][l]=min(mn[i][l-1],mn[i+(1<<(l-1))][l-1]);
}
}
}
int RMQ(int l,int r,int w)
{
int k = __lg(r - l + 1);
int ans;
if(!w) ans=max(mx[l][k],mx[r-(1<<k)+1][k]);
else ans=min(mn[l][k],mn[r-(1<<k)+1][k]);
return ans;
}
bool check(int l, int r) {
return RMQ(l, r, 0) - RMQ(l, r, 1) > k;
}
void solve() {
n = rd(), m = rd();
for (int i = 1; i <= n; ++i) {
mx[i][0] = rd();
mn[i][0] = mx[i][0];
}
st(n);
while (m--) {
ll ans = 0;
k = rd();
int head = 1, rear = 1;
while (head <= n) {
while (rear <= n && !check(head, rear)) rear++;
if (rear > n) {
head++;
continue;
}
ans += n - rear + 1;
head++;
}
printf("%lld\n", ans);
}
}
int main() {
int t = 1;
while (t--) solve();
return 0;
}
顺丰集团工作强度 274人发布
查看9道真题和解析