zoukankan      html  css  js  c++  java
  • 11.1 校内模拟赛题解报告

    期望得分:100 + 30 + 0 = 130

    实际得分:70 + 30 + 0 = 100

    总结

    考试傻事集合:

    T1 用线段树写了个求单调不降的序列的最大值和最小值。

    T1 以为 (mlog^2n) 能跑过 (10^6) 的数据。

    T2 (dp) 初始值赋错,幸好有大样例 = =;

    T1 median

    题面

    算法一

    直接二分中位数,然后用 upper_bound 直接 check 就行。

    复杂度 (O(mlog^2 n))

    期望得分:(70pts)

    code

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int MAXN = 7e5 + 5;
    const int INF = 1e9 + 7;
    int read() {
      int x = 0, f = 1; char c = getchar();
      while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
      while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
      return x * f;
    }
    int n, m, a[MAXN], Mid, b[MAXN];
    int l_1, l_2, r_1, r_2; 
    bool Check(int x) {
      int ret_1 = upper_bound(a + l_1, a + r_1 + 1, x) - a;
      int ret_2 = upper_bound(b + l_2, b + r_2 + 1, x) - b;
      ret_1--, ret_2--;
      ret_1 = ret_1 - l_1 + 1, ret_2 = ret_2 - l_2 + 1;
      if(ret_1 + ret_2 >= Mid) return true;
      return false;
    }
    int tmp[MAXN * 2];
    signed main(){
      n = read(), m = read();
      for (int i = 1; i <= n; i++) a[i] = read();
      for (int i = 1; i <= n; i++) b[i] = read();
      for (int i = 1; i <= m; i++) {
      	 int opt = read();
      	 if(opt == 1) {
      	   int x = read(), y = read(), z = read();
    	   if(x == 0) a[y] = z;
      	   else b[y] = z;
    	 }
    	 else {
    	   l_1 = read(), r_1 = read(), l_2 = read(), r_2 = read();
    	   int l = min(a[l_1], b[l_2]), r = max(a[r_1], b[r_2]), Ans;
    	   Mid = (r_1 - l_1 + 1) + (r_2 - l_2 + 1);
    	   Mid = Mid / 2 + 1;
    	   while(l <= r) {
    	   	 int mid = (l + r) >> 1;
    	     if(Check(mid)) Ans = mid, r = mid - 1;
    		 else l = mid + 1;  
    	   }
    	   cout<<Ans<<"
    ";
    	 }
      }
      return 0;
    }
    

    算法二

    (a) 中二分出一个中位数 (x),然后在 (b) 中找出它的期望位置 (pos)。如果 (b_{pos - 1} leq x leq b_{pos + 1}) 那么枚举出来的数就是合法的。

    注意中位数在 (a)(b) 中都可能会出现,所以要做两次二分。

    这个算法要特判很多情况,所以我就没写。

    复杂度 (O(mlogn))

    期望得分:(100pts)

    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int MAXN = 5e5 + 10; 
    int n,m,t;
    int a[MAXN],b[MAXN];
    inline int read(){
    	int s = 0, f = 0;char ch = getchar();
    	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
    	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    inline int Max(int x,int y) {return x > y ? x : y;}
    inline int Min(int x,int y) {return x < y ? x : y;}
    inline int Get_Ans_A(int l,int r,int L,int R)
    {
      int Len = r - l + 1 + R - L + 1,id = Len / 2;
      int LL = l,RR = r;
      while(LL <= RR) {
        int mid = (LL + RR) >> 1;
        int pos = id - (mid - l + 1) + L;
        if(mid - l == id && a[mid] <= b[L]) return a[mid];
        if(pos > R) {LL = mid + 1;continue;}
        if(pos < L) {RR = mid - 1;continue;}
        if((b[pos + 1] >= a[mid] || pos == R) && a[mid] >= b[pos]) return a[mid];
        if(a[mid] < b[pos]) LL = mid + 1;
        else RR = mid - 1; 
      }
      return 0;
    }
    inline int Get_Ans_B(int l,int r,int L,int R)
    {
      int Len = r - l + 1 + R - L + 1,id = Len / 2;
      int LL = l,RR = r;
      while(LL <= RR) {
        int mid = (LL + RR) >> 1;
        int pos = id - (mid - l + 1) + L;
        if(mid - l == id && b[mid] <= a[L]) return b[mid];
        if(pos > R) {LL = mid + 1;continue;}
        if(pos < L) {RR = mid - 1;continue;}
        if((a[pos + 1] >= b[mid] || pos == R) && b[mid] >= a[pos]) return b[mid];
        if(b[mid] < a[pos]) LL = mid + 1;
        else RR = mid - 1; 
      }
      return 0;
    }
    signed main(){
      n = read(),m = read();
      for(int i = 1;i <= n;i ++) a[i] = read();
      for(int i = 1;i <= n;i ++) b[i] = read();
      while(m --) {
        int op = read();
        if(op == 1) {
          int x = read(),y = read(),z = read();
          if(x) b[y] = z;
          else a[y] = z;
        }
        else {
          int l = read(),r = read(),L = read(),R = read();
          int Ans = Get_Ans_A(l,r,L,R);
          if(!Ans) Ans = Get_Ans_B(L,R,l,r); 
          printf("%d
    ",Ans);
        }
      }
      return 0;
    }
    

    算法三

    递归求解。

    假设当前取得是区间第 (k) 大,将 (k) 折半,放在两个序列的对应位置上,(s)(t),比较一下 (a_s)(b_t) , 假设 (a_s < b_t) ,那么答案就可以变为求区间([s + 1, r_1], [l_2, r_2]) 的第 (frac {k}{2}) 大的数。(因为 (a) 序列比 (a[s]) 小的那 些 数 一 定 可 以 全 部 舍 去 ),然后递归即可。

    复杂度 (O(mlogn))

    code

    /*
    递归求解 
    */
    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 5e5 + 5;
    int read() {
      int x = 0, f = 1; char c = getchar();
      while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
      while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
      return x * f;
    }
    int n, m;
    int a[MAXN], b[MAXN];
    int Kth(int ta[], int sta, int tb[], int stb, int k) { 
       if (sta > stb) return Kth(tb, stb, ta, sta, k); // 保证前面那个是短的
       if (sta == 0) return tb[k];  
       if (k == 1) return min(ta[1], tb[1]);
       int ka = min(sta, k / 2), kb = k - ka;
       if (ta[ka] < tb[kb]) return Kth(ta + ka, sta - ka, tb, stb, k - ka);
       return Kth(ta, sta, tb + kb, stb - kb, k - kb);
    }
    int Query(int la, int ra, int lb, int rb) {
       int sta = ra - la + 1, stb = rb - lb + 1, siz = sta + stb;
       return Kth(a + la - 1, sta,  b + lb - 1, stb, siz / 2 + 1);
    }
    int main(){
      n = read(), m = read();
      for (int i = 1; i <= n; i++) a[i] = read();
      for (int i = 1; i <= n; i++) b[i] = read();
      for (int i = 1; i <= m; i++) {
      	 int opt = read();
      	 if(opt == 1) {
      	    int x = read(), y = read(), z = read();
    		if(x == 0) a[y] = z;
    		else b[y] = z;
    	  }
    	  else {
    	  	int l_1 = read(), r_1 = read(), l_2 = read(), r_2 = read();
    	  	printf("%d
    ", Query(l_1, r_1, l_2, r_2));
    	  }
      }
      return 0;
    }
    
    

    T2 min

    题面

    算法一:

    模拟题意,直接 (dp)

    (f_i) 表示前 (i) 个位置,划分得到的最大价值。

    转移方程:

    (dp_{i} = max_{j = 0}^{j = i - 1}{dp[j] + f(min_{x = j + 1}^{i} a_x)})

    (dp_0 = 0)

    注意初始化。

    复杂度 (O(n^2))

    期望得分:30pts

    memset(dp, -0x3f3f3f3f3f3f, sizeof dp);
      dp[0] = 0;
      for (int i = 1; i <= n; i++) {
      	for (int j = 0; j < i; j++) {
      	  int x = Query(j + 1, i);
      	  dp[i] = max(dp[i], dp[j] + A * x * x * x + B * x * x + C * x + D);	
    	} 
      }
      cout<<dp[n];
    

    算法二

    (A = 0, B = 0, C leq 0)

    此时 (f(x) = Cx + D)

    (Cy + D = 0)

    case 1(z > y) 时:

    (Cz + D < 0)

    case 2(w < y)

    (Cw + D > 0)

    对于 case 1 我们可以把它放到 case 2 中的一组中,这样就不会计算 (case ~1) 的贡献,因为 (w < z),如果没有 case 2 这种情况,那就只分一组。

    (sum f(a_i)(f(a_i) > 0))

    if(A == 0 && B == 0 && C <= 0) {
      	int Ans = 0;
    	for (int i = 1; i <= n; i++) {
      	   if(a[i] * C + D >= 0) Ans += a[i] * C + D;	 
    	}
    	if(Ans > 0) cout<<Ans;
    	else {
    	  int Min = INF;
    	  for (int i = 1; i <= n; i++) Min = min(a[i], Min); 
    	  cout<<Min * C + D;
    	}
    	return 0;
      }
    

    算法三

    用单调栈维护 (g_x = min_{x = j}^{i}a_x) 。具体地,单调栈中的元素 (l_1, l_2dots l_m) 表示 (g_{l_i} eq g_{l_i - 1}) 的每个 (l_i)(就是最小值变化的转折
    点) , 那么有 (forall x in[l_i, l_{i + 1} - 1], g_x) 相同,此时 (dp) 值最大的那个点一定最优秀,于是维护 (h_i = max_{x = l_i}^{l_i + 1}{dp[x]}),表示每个取最小值元素对应区间的最优答案。

    这样的话,每一次的答案就是 (max{h_i + f(g_{l_i})}),采用一棵线段树
    或者可删除堆维护单调栈即可。

    复杂度 (O(nlogn))

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int MAXN = 524287;
    const long long inf = 0x3f3f3f3f3f3f3f3f;
    int read() {
      int x = 0, f = 1; char c = getchar();
      while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
      while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
      return x * f;
    }
    int a[MAXN], st[MAXN], tp, n, A, B, C, D;
    ll T[MAXN << 1], f[MAXN], mx[MAXN];
    void Up(int i, ll x) {
      for (T[i += MAXN] = x; i >>= 1;) T[i] = max(T[i << 1], T[i << 1 | 1]); 
    }
    ll Cal(ll x) {return ((A * x + B) * x + C) * x + D; }
    int main(){
      n = read(), A = read(), B = read(), C = read(), D = read();
      for (int i = 1; i <= n; i++) a[i] = read();
      memset(T, -0x3f, sizeof T);
      f[0] = 0, mx[1] = 0, st[tp = 1] = a[1];
      Up(1, Cal(a[1]));
      for (int i = 1; i <= n; i++) {
      	 f[i] = T[1]; ll x = f[i];
      	 while(st[tp] > a[i + 1] && tp) x = max(x, mx[tp]), Up(tp--, -inf);
    	 st[++tp] = a[i + 1], mx[tp] = x, Up(tp, x + Cal(st[tp]));
      }
      cout<<f[n];
      return 0;
    }
    
    

    T3

    题面

    std

    #include<cstdio>
    #include<algorithm>
    #define ls p << 1
    #define rs p << 1 | 1
    #define rt 1, 1, Q
    const int N = 1e5 + 10, Y = 2e5 + 10, P = 1e9 + 7;
    int ri() {
    	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
    	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
    }
    int t[N << 2], tm[N << 2], c[Y], b[Y], l[Y], r[Y], pr[Y], to[Y << 1], nx[Y << 1], Q, n, m, k, H;
    void add(int x, int p) {to[++H] = 1LL * to[pr[x]] * (1 - p) % P; nx[H] = pr[x]; pr[x] = H;}
    struct D {int l, r;} q[N];
    struct X {int x, y, p;}p[Y];
    bool cmp1(X a, X b) {return a.y < b.y;}
    bool cmp2(D a, D b) {return a.l == b.l ? a.r < b.r : a.l < b.l;}
    int Pow(int x, int k) {
    	int r = 1;
    	for(;k;x = 1LL * x * x % P, k >>= 1) if(k & 1) r = 1LL * r * x % P;
    	return r;
    }
    void B(int p, int L, int R) {
    	tm[p] = 1; if(L == R) return void(t[p] = 1);
    	int m = L + R >> 1; B(ls, L, m); B(rs, m + 1, R); 
    	t[p] = t[ls] + t[rs];
    }
    void Tag(int p, int v) {tm[p] = 1LL * tm[p] * v % P; t[p] = 1LL * t[p] * v % P;}
    void Pd(int p) {if(tm[p] != 1) Tag(ls, tm[p]), Tag(rs, tm[p]), tm[p] = 1;}
    void M(int p, int L, int R, int st, int ed, int v) {
    	if(L == st && ed == R) return Tag(p, v);
    	int m = L + R >> 1; Pd(p);
    	if(st <= m) M(ls, L, m, st, std::min(ed, m), v);
    	if(ed > m) M(rs, m + 1, R, std::max(st, m + 1), ed, v);
    	t[p] = (t[ls] + t[rs]) % P;
    }
    void C(int x) {
    	if(l[x] > r[x]) return ; 
    	int m = Pow(1 - (to[pr[x]] - b[x]) % P, P - 2); pr[x] = nx[pr[x]]; 
    	M(rt, l[x], r[x], 1LL * (1 - (to[pr[x]] - b[x]) % P) * m % P);
    }
    int main() {
    	//freopen("max.in","r",stdin);
    	//freopen("max.out","w",stdout);
    	n = ri(); m = ri(); Q = ri(); int tp = 0;
    	for(int i = 1;i <= m; ++i) {
    		int x = ri(), y = ri(), px = ri();
    		if(!px || !y) continue;
    		p[++tp].x = x; p[tp].y = y; p[tp].p = px;
    	}
    	std::sort(p + 1, p + tp + 1, cmp1);
    	for(int i = 1;i <= n; ++i) to[++H] = 1, pr[i] = H;
    	for(int i = 1;i <= tp; ++i) add(p[i].x, p[i].p);
    	for(int i = 1;i <= n; ++i) b[i] = to[pr[i]];
    	for(int i = 1;i <= Q; ++i) q[i].l = ri(), q[i].r = ri();
    	std::sort(q + 1, q + Q + 1, cmp2);
    	int L = 1, R = 0; 
        for(int i = 1;i <= n; ++i) {
            for(;L <= R && q[L].r < i; ++L) ;
            for(;q[R + 1].l <= i && R < Q; ++R) ;
            l[i] = L; r[i] = R;
        } 
        B(rt); int A = 0; p[0].y = 0;
        for(int i = tp, j; i; i = j) {
        	for(j = i;p[j].y == p[i].y && j; --j) C(p[j].x);
        	A = (A + 1LL * t[1] * (p[i].y - p[j].y)) % P;
        }
        A = (1LL * p[tp].y * Q - A) % P;
        printf("%d
    ", (A + P) % P);
    	return 0;
    }
    
  • 相关阅读:
    JS基础_自增和自减
    计算机组成原理
    SyntaxHighlighter
    10个经典的C语言面试基础算法及代码
    知名互联网公司面试题
    计算机网络基础知识(笔试题)
    面试准备之常见上机题目搜罗
    小米2013年校园招聘笔试题-简单并查集
    2014华为上机试题
    C++学习笔记
  • 原文地址:https://www.cnblogs.com/Arielzz/p/15495902.html
Copyright © 2011-2022 走看看