首页 > 其他分享 >HDU-ACM 2024 Day3

HDU-ACM 2024 Day3

时间:2024-08-13 22:06:32浏览次数:16  
标签:HDU return int res mid Day3 2024 include Mod

T1004 游戏(HDU 7460)

注意到对于两个人,他们 \(t\) 轮后能力值相同的概率只与他们初始时的能力差有关,所以我们先 \(\text{FFT}\) 求出 \(|a_i - a_j| = k\) 的 \((i, j)\) 对数。

构造多项式 \(F(x) = (p_1 x^2 + p_2 + p_3x)\),其中 \(p_1, p_2, p_3\),分别表示在一轮中两个人相对能力值变化为 \(+1/-1/0\) 的概率,这三个数容易用 \(n\) 表示,我们现在的任务是 \(\forall k \in [0, V)\),求 \([x^{t + k}] F(x)^t\)。

令 \(G(x) = F(x)^t\),考虑对 \(G\) 求导,我们有 \(G'(x) = t \times F'(x) \times F(x)^{t - 1} \iff G'(x) \times F(x) = t \times F'(x) \times G(x)\),将 \(F\) 和 \(F'\) 展开可得 \(G'(x) \times (p_1 x^2 + p_2 + p_3x) = t \times (2p_1x + p_3) \times G(x)\),取 \(G\) 的 \(i\) 次项系数即可得到 \(G\) 的系数的递推式。

时间复杂度 \(O(V \log V + t)\)。

Code
#include <iostream>
#include <vector>
#include <algorithm>
#include <complex>
#include <cmath>

using namespace std;
using LL = long long;
using Cp = complex<double>;

const int N = 1e6 + 5, T = 2e7 + 5; 
const int Mod = 998244353;

int power (int x, int y = Mod - 2) {
  int res = 1;
  while (y) {
    if (y & 1) {
      res = 1ll * res * x % Mod;
    } 
    x = 1ll * x * x % Mod;
    y >>= 1;
  }
  return res;
}

int m, t;
int inv[T], g[T];
LL a[N];

namespace FFT {
  const double pi = acos(-1);
  int len = 1; 
  vector<int> r;

  void FFT (vector<Cp> &a, int v) {  
    for (int i = 0; i < len; ++i) {
      if (i < r[i]) {
        swap(a[i], a[r[i]]);
      }
    }
    for (int i = 1; i < len; i <<= 1) {
      for (int j = 0; j < len; j += (i << 1)) {
        for (int k = 0; k < i; ++k) {
          Cp p = a[j + k], q = Cp(cos(pi * k / i), sin(pi * k / i) * v) * a[j + k + i];
          a[j + k] = p + q, a[j + k + i] = p - q; 
        }
      }
    }
  }

  vector<LL> convolution (vector<int> &a, vector<int> &b) {
    int n = a.size() - 1, m = b.size() - 1;    
    for (; len <= n + m; len <<= 1) {
    }
    a.resize(len), b.resize(len), r.resize(len);
    vector<Cp> A(len);
    for (int i = 0; i < len; ++i) {
      A[i] = Cp(a[i], b[i]); 
      r[i] = (r[i >> 1] >> 1) | (i & 1) * (len >> 1); 
    }
    FFT(A, 1);
    for (int i = 0; i < len; ++i) {
      A[i] *= A[i];
    }
    FFT(A, -1);
    vector<LL> res(n + m + 1); 
    for (int i = 0; i <= n + m; ++i) {
      res[i] = LL(A[i].imag() / len / 2 + 0.5);
    }
    return res;
  }
}

int main () {
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  inv[1] = 1; 
  for (int i = 2; i < T; ++i) {
    inv[i] = 1ll * (Mod - Mod / i) * inv[Mod % i] % Mod;
  }
  int tmpn; 
  cin >> tmpn >> t;
  vector<int> arr(tmpn);
  for (int i = 0; i < tmpn; ++i) {
    cin >> arr[i];
    m = max(m, arr[i]);
  }
  vector<int> c(m + 1);
  for (auto x : arr) {
    ++c[x];
  }
  for (auto t : c) {
    a[0] += 1ll * (t - 1) * t / 2; 
  }
  vector<int> _c = c; 
  reverse(_c.begin(), _c.end());
  vector<LL> z = FFT::convolution(c, _c);
  for (int i = 1; i < m; ++i) {
    a[i] += z[i + m];
  }
  --m;
  int p1 = 2ll * (tmpn - 2) * inv[tmpn] % Mod * inv[tmpn - 1] % Mod, p2 = p1, p3 = (1 - p1 * 2 + Mod * 2) % Mod;
  int p1i = 1ll * power(p1) * (Mod - 1) % Mod;
  g[t * 2] = power(p1, t); 
  if (t) g[t * 2 - 1] = 1ll * power(p1, t - 1) * p3 % Mod * t % Mod;
  for (int i = t * 2 - 1; i >= t; --i) {
    g[i - 1] = ((1ll * (t - i + Mod) * p3 % Mod * g[i] - 1ll * (i + 1) * p2 % Mod * g[i + 1] + 1ll * Mod * Mod) % Mod) * inv[t * 2 + 1 - i] % Mod * p1i % Mod;  
  } 
  int ans = 0; 
  for (int i = 0; i <= min(t, m); ++i) {
    ans = (ans + 1ll * g[i + t] * (a[i] % Mod)) % Mod;
  }
  cout << ans << '\n';  
  return 0; 
}

T1005 数论(HDU 7461)

考虑固定一个端点向左/右扫,可以得到 \(O(\log n)\) 个 \(\gcd\) 相同的段(\(\gcd\) 每次变化至少减半),每段形如 \((g, l, r, t)\),表示一个端点为 \(t\),另一个端点在 \([l, r]\) 中,这样构成的区间都满足 \(\gcd = g\),总段数 \(O(n \log n)\),找段考虑二分 + ST 表,时间复杂度 \(O(n \log^2 n)\)。

对答案进行容斥,算出总方案数和不包含 \(i\) 的方案数,不包含一个数又可以拆成一段前缀和一段后缀任选,所以我们只需对前缀和后缀分别做 \(\text{dp}\) 即可。

对于前缀而言,我们枚举 \(\gcd\) 然后分别算贡献,对于某个 \(\gcd = g\) 有若干段 \((l, r, t)\),我们按 \(t\) 排序,设 \(f_i\) 表示在 \([1, i]\) 中选若干满足 \(\gcd = g\) 的不交区间,最后一个区间右端点为 \(i\) 的方案数,转移方程是 \(f_t = \sum\limits_{i = l}^{r} \sum\limits_{j = 0}^{i - 1} f_j\)。考虑一个 \(f_j\) 的贡献,对于 \(j < l\),\(f_j\) 系数为 \(r - l + 1\),对于 \(j \in [l, r]\),\(f_j\) 系数构成公差为 \(-1\),末项为 \(0\) 的等差数列。相当于单点修改,区间和,区间等差数列加权和,线段树容易维护。

后缀类似,设 \(g_i\) 表示在 \([i, n]\) 中选若干满足 \(\gcd = g\) 的不交区间,第一个区间以 \(i\) 为左端点的方案数,再开一棵线段树维护即可。

时间复杂度 \(O(n \log^2 n)\)。

Code
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <chrono>
#include <cassert>

#define lc (k << 1)
#define rc ((k << 1) | 1)

using namespace std;
using LL = long long;
using uLL = unsigned long long;

uLL Get_time () { return chrono::steady_clock::now().time_since_epoch().count(); }

const int N = 1e5 + 5, M = 17; 
const int Mod = 998244353;

int n, allsum;
int a[N], st[N][M], diff[N];

struct Tr {
  int l, r, t; 
}; 

namespace Pre_Seg {
  const int T = N * 4;

  struct Tree {
    int sum[T], rsum[T], len[T];

    void Build (int k, int L = 0, int R = n) {
      len[k] = R - L + 1;
      if (L == R) return;
      int mid = (L + R) >> 1;
      Build(lc, L, mid);
      Build(rc, mid + 1, R); 
    }

    void Modify (int k, int x, int y, int L = 0, int R = n) {
      if (L == R) {
        sum[k] = y;
        return; 
      }
      int mid = (L + R) >> 1;
      if (x <= mid) { 
        Modify(lc, x, y, L, mid);
      }
      else {
        Modify(rc, x, y, mid + 1, R);
      }
      sum[k] = (sum[lc] + sum[rc]) % Mod;
      rsum[k] = (rsum[lc] + rsum[rc] + 1ll * sum[lc] * len[rc]) % Mod;
    }

    LL Query_sum (int k, int l, int r, int L = 0, int R = n) {
      if (l > r) return 0; 
      if (l <= L && r >= R) {
        return sum[k];
      }
      int mid = (L + R) >> 1; 
      LL res = 0;
      if (l <= mid) {
        res = (res + Query_sum(lc, l, r, L, mid));
      }
      if (r > mid) {
        res = (res + Query_sum(rc, l, r, mid + 1, R));
      }
      return res;
    }

    LL Query_rsum (int k, int l, int r, int L = 0, int R = n) {
      if (l <= L && r >= R) {
        return (rsum[k] + 1ll * (r - R) * sum[k]) % Mod;
      }
      int mid = (L + R) >> 1;
      LL res = 0; 
      if (l <= mid) {
        res = (res + Query_rsum(lc, l, r, L, mid));
      }
      if (r > mid) {
        res = (res + Query_rsum(rc, l, r, mid + 1, R));
      }
      return res;
    }
  };
}

namespace Suf_Seg {
  const int T = N * 4;

  struct Tree {
    int sum[T], rsum[T], len[T];

    void Build (int k, int L = 1, int R = n + 1) {
      len[k] = R - L + 1;
      if (L == R) return;
      int mid = (L + R) >> 1;
      Build(lc, L, mid);
      Build(rc, mid + 1, R); 
    }

    void Modify (int k, int x, int y, int L = 1, int R = n + 1) {
      if (L == R) {
        sum[k] = y;
        return; 
      }
      int mid = (L + R) >> 1;
      if (x <= mid) { 
        Modify(lc, x, y, L, mid);
      }
      else {
        Modify(rc, x, y, mid + 1, R);
      }
      sum[k] = (sum[lc] + sum[rc]) % Mod;
      rsum[k] = (rsum[lc] + rsum[rc] + 1ll * len[lc] * sum[rc]) % Mod; 
    }

    LL Query_sum (int k, int l, int r, int L = 1, int R = n + 1) {
      if (l > r) return 0; 
      if (l <= L && r >= R) {
        return sum[k];
      }
      int mid = (L + R) >> 1; 
      LL res = 0;
      if (l <= mid) {
        res = (res + Query_sum(lc, l, r, L, mid));
      }
      if (r > mid) {
        res = (res + Query_sum(rc, l, r, mid + 1, R));
      }
      return res;
    }

    LL Query_rsum (int k, int l, int r, int L = 1, int R = n + 1) {
      if (l <= L && r >= R) {
        return (rsum[k] + 1ll * (L - l) * sum[k]) % Mod;
      }
      int mid = (L + R) >> 1;
      LL res = 0; 
      if (l <= mid) {
        res = (res + Query_rsum(lc, l, r, L, mid));
      }
      if (r > mid) {
        res = (res + Query_rsum(rc, l, r, mid + 1, R));
      }
      return res;
    }
  };
}

Pre_Seg::Tree pret;
Suf_Seg::Tree suft;

signed main () {
  // freopen("tmp.in", "r", stdin);
  // freopen("1005.out", "w", stdout);
  cin.tie(0)->sync_with_stdio(0);
  uLL st0 = Get_time();
  cin >> n; 
  for (int i = 1; i <= n; ++i) { 
    cin >> a[i];
  }
  pret.Build(1), pret.Modify(1, 0, 1);
  suft.Build(1), suft.Modify(1, n + 1, 1);
  for (int i = 1; i <= n; ++i) {
    st[i][0] = a[i];
  }
  for (int k = 1; k < M; ++k) {
    for (int i = 1; i + (1 << k) - 1 <= n; ++i) {
      st[i][k] = __gcd(st[i][k - 1], st[i + (1 << (k - 1))][k - 1]);
    }
  }
  auto Query = [&](int l, int r) -> int {
    int k = log2(r - l + 1);
    return __gcd(st[l][k], st[r - (1 << k) + 1][k]);
  }; 
  map<int, vector<Tr>> mpre;
  map<int, vector<Tr>> msuf;
  for (int i = 1; i <= n; ++i) {
    for (int p = i, l = 1, r = p; p; p = l - 1, l = 1, r = p) {
      int g = Query(p, i);
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (Query(mid, i) == g) {
          r = mid - 1;  
        }
        else {
          l = mid + 1; 
        }
      }
      auto it = mpre.find(g);
      if (it == mpre.end()) { 
        mpre.insert({g, vector<Tr>{{l, p, i}}});
      }
      else {
        it->second.push_back({l, p, i});
      }
    }
    for (int p = i, l = p, r = n; p <= n; p = r + 1, l = p, r = n) {
      int g = Query(i, p);
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (Query(i, mid) == g) {
          l = mid + 1; 
        }
        else {
          r = mid - 1; 
        }
      }
      auto it = msuf.find(g);
      if (it == msuf.end()) {
        msuf.insert({g, vector<Tr>{{p, r, i}}});
      }
      else {
        it->second.push_back({p, r, i});
      }
    }
  }
  for (auto ipre = mpre.begin(), isuf = msuf.begin(); ipre != mpre.end(); ++ipre, ++isuf) {
    assert(ipre->first == isuf->first);
    vector<Tr> vp = ipre->second, sp = isuf->second;
    sort(vp.begin(), vp.end(), [&](Tr i, Tr j) -> bool {
      return i.t < j.t;
    });
    sort(sp.begin(), sp.end(), [&](Tr i, Tr j) -> bool {
      return i.t > j.t;
    });
    vector<int> dpoint;
    for (auto i : vp) {
      dpoint.push_back(i.t);
      int f = (pret.Query_sum(1, 0, i.l - 1) % Mod * (i.r - i.l + 1) + pret.Query_rsum(1, i.l, i.r)) % Mod;
      pret.Modify(1, i.t, f);
      allsum = (allsum + f) % Mod;
    }
    for (auto i : sp) {
      dpoint.push_back(i.t);
      int f = (suft.Query_sum(1, i.r + 1, n + 1) % Mod * (i.r - i.l + 1) + suft.Query_rsum(1, i.l, i.r)) % Mod;
      suft.Modify(1, i.t, f);
    }
    sort(dpoint.begin(), dpoint.end());
    dpoint.resize(unique(dpoint.begin(), dpoint.end()) - dpoint.begin());
    int la = 0;
    auto Range_add = [&](int l, int r) -> void {
      if (l > r) return; 
      int x = ((pret.Query_sum(1, 1, l - 1) % Mod + 1) * (suft.Query_sum(1, l + 1, n) % Mod + 1) % Mod - 1 + Mod) % Mod;
      diff[l] = (diff[l] + x) % Mod;
      diff[r + 1] = (diff[r + 1] - x + Mod) % Mod;
    }; 
    for (auto i : dpoint) {
      Range_add(la + 1, i - 1);
      Range_add(i, i);
      la = i;
    }
    Range_add(la + 1, n);
    for (auto i : vp) {
      pret.Modify(1, i.t, 0);
    }
    for (auto i : sp) {
      suft.Modify(1, i.t, 0);
    }
  }
  for (int i = 1; i <= n; ++i) {
    diff[i] = (diff[i] + diff[i - 1]) % Mod;
  }
  for (int i = 1; i <= n; ++i) {
    cout << (allsum - diff[i] + Mod) % Mod << ' ';
  }
  cout << '\n';
  uLL ed0 = Get_time(); 
  // cerr << "Time = " << (ed0 - st0) / int(1e6) << '\n';
  return 0; 
}

T1006 字符串(HDU 7462)

不会。

T1009 圣芙蕾雅(HDU 7465)

不会。

T1010 绘世之卷(HDU 7466)

首先带删除肯定是不好做的,考虑线段树分治一下,变成插入和撤销,这样我们只需在加入一个数时,算它和其他数的贡献。

根号分治,令 \(d = \lfloor \sqrt n \rfloor\)。注意到当集合大小 \(|S| > d\) 时,答案 \(\le d\),证明:容易说明一定存在一对 \((x, y)\) 满足 \(1 \le y - x \le d\),如果 \(x \le d\) 那么用 \(x\) 做被除数,否则用 \(y\) 做被除数即可。

当 \(|S| \le d\) 时直接暴力和每个元素匹配算贡献。当 \(|S| > d\) 时,分类讨论,假设当前加入的是 \(x\)。

  • 若 \(ky + r = x \iff ky = x - r\),枚举 \(r\),在插入 \(y\) 时预处理 \(k \in [0, d]\) 即可。
  • 若 \(kx + r = y\),枚举 \(k\),只需找到 \(kx\) 的前驱,插入一个数 \(y\) 时修改 \([y, y + d]\) 的前驱即可。

两种修改操作都方便撤销。

时间复杂度 \(O(n \sqrt n \log n)\)。

Code
#include <iostream>
#include <vector>
#include <set>
#include <cmath>

using namespace std;

#define lc (k << 1)
#define rc ((k << 1) | 1)

const int N = 5e4 + 5, Inf = 1e9, T = N * 4;
const int S = 1e6;

int n, d, q, cur, ans[N], pre[N], mik[N];
vector<int> vec[T];
set<int> st;
int len1, len2;
pair<int, int> stpre[S], stmik[S];

void Add (int k, int l, int r, int x, int L = 1, int R = q) {
  if (l <= L && r >= R) {
    vec[k].push_back(x);
    return; 
  }
  int mid = (L + R) >> 1;
  if (l <= mid) {
    Add(lc, l, r, x, L, mid);
  }
  if (r > mid) { 
    Add(rc, l, r, x, mid + 1, R);
  }
}

void Solve (int k, int L = 1, int R = q) {
  int lst = cur, tmp1 = len1, tmp2 = len2;
  for (auto x : vec[k]) {
    if (st.size() >= d) {
      for (int r = 0; r <= d && x - r; ++r) {
        cur = min(cur, mik[x - r] + r);
      }
      for (int k = 0; k <= d && x * k <= n; ++k) {
        cur = min(cur, x * k - pre[x * k] + k);
      }
    }
    else {
      for (auto y : st) {
        cur = min(cur, min(x / y + x % y, y / x + y % x));
      }
    }
    st.insert(x);
    for (int k = 0; k <= d && x * k <= n; ++k) {
      if (k < mik[x * k]) {
        stmik[++len1] = {x * k, mik[x * k]};
        mik[x * k] = k;
      } 
    }
    for (int i = x; i <= min(n, x + d); ++i) {
      if (x > pre[i]) {
        stpre[++len2] = {i, pre[i]};
        pre[i] = x;
      }
      else {
        break;
      }
    }
  }
  if (L == R) 
    ans[L] = cur;
  else {
    int mid = (L + R) >> 1;
    Solve(lc, L, mid);
    Solve(rc, mid + 1, R);
  }
  cur = lst;
  for (auto x : vec[k]) 
    st.erase(x);
  for (; len1 > tmp1; --len1)  
    mik[stmik[len1].first] = stmik[len1].second;
  for (; len2 > tmp2; --len2) 
    pre[stpre[len2].first] = stpre[len2].second;
}

int main () {
  cin.tie(0)->sync_with_stdio(0);
  int T;
  cin >> T;
  while (T--) {
    cin >> n >> q, d = sqrt(n);
    vector<int> occ(n + 1, -1);
    fill(vec + 1, vec + q * 4 + 1, vector<int>());
    for (int o, x, i = 1; i <= q; ++i) {
      cin >> o >> x;
      if (o == 0) {
        Add(1, occ[x], i - 1, x);
        occ[x] = -1;
      }
      else {
        occ[x] = i;
      }
    }
    for (int i = 1; i <= n; ++i) {
      if (occ[i] != -1) {
        Add(1, occ[i], q, i);
      }
    }
    fill(mik + 1, mik + n + 1, Inf);
    fill(pre, pre + n + 1, -Inf);
    cur = N, Solve(1);
    for (int i = 1; i <= q; ++i) {
      cout << (ans[i] == N ? -1 : ans[i]) << '\n';
    }
  }
  return 0; 
}

标签:HDU,return,int,res,mid,Day3,2024,include,Mod
From: https://www.cnblogs.com/hztmax0/p/18354389

相关文章

  • 微软NET FrameWork离线运行库+离线安装包合集,一键安装版 微软.NET离线运行库合集2024
     微软.NET离线运行库合集2024最新版是一款专为便捷、高效地管理.NET运行库而设计的工具。这款软件集成了各种版本的.NET运行库,并提供了离线安装的功能,使用户能够在没有网络连接的情况下轻松地安装所需的运行库。该软件的出现极大地简化了.NET开发环境的配置和维护过程。用户可......
  • .NET周刊【8月第1期 2024-08-04】
    国内文章EFCore性能优化技巧https://www.cnblogs.com/baibaomen-org/p/18338447这篇文章介绍了在代码层面上优化EFCore实例池和拆分查询的方法。首先,文章建议使用DbContext实例池来重复利用实例,避免资源浪费,并提供相关使用示例。其次,文章讨论了笛尔卡乘积对复杂查询性能的影......
  • 【专题】2024无人驾驶网约车乘坐意愿调查报告合集PDF分享(附原数据表)
     原文链接:https://tecdat.cn/?p=37335 科技迅猛发展,无人驾驶技术从科幻走进现实,2024年无人驾驶网约车成热议话题。阅读原文,获取专题报告合集全文,解锁文末208份无人驾驶网约车相关行业研究报告。报告表明,近60%受访者期待,00后更积极,80后较谨慎。性别上男性更乐观,城市级别......
  • ChatGPT 大模型核心算法深度分析 2024
    在分析核心算法之前,我们先了解chatGPT相关技术发展进程首先介绍自然语言处理、大规模预训练语言模型以及ChatGPT技术的发展历程,接着就ChatGPT的技术优点和不足进行分析,然后讨论核心算法。1.1自然语言处理的发展历史人类语言(又称自然语言)具有无处不在的歧义性、高度......
  • 2024牛客暑期多校训练营9
    Preface久违的多校,又被徐神带飞力这场总体可做题挺多的,前期出题也还算稳,但中间祁神写H睿智错误频发直接红温爆交了7发但无所谓徐神会出手,上机把当时只过了两个队的G秒了,然后我爬上去把B,C写了然后对着D罚坐一整场赛后经典看不懂出题人的一句话题解,坐等视频讲解吧(虽......
  • DRM:清华提出无偏差的新类发现与定位新方法 | CVPR 2024
    论文分析了现有的新类别发现和定位(NCDL)方法并确定了核心问题:目标检测器往往偏向已知的目标,忽略未知的目标。为了解决这个问题,论文提出了去偏差区域挖掘(DRM)方法,以互补的方式结合类无关RPN和类感知RPN进行目标定位,利用未标记数据的半监督对比学习来改进表征网络,以及采用简单高效的m......
  • 2024亚太杯数学建模b题基于机器学习回归的洪水预测模型研究
    本届亚太杯中文赛项已经结束,本文分享我的解决思路。摘 要洪水的频率和严重程度与人口增长趋势相近。迅猛的人口增长,扩大耕地,围湖造田,乱砍滥伐等人为破坏不断地改变着地表状态,改变了汇流条件,加剧了洪灾程度。2023年,全球洪水造成了数十亿美元的经济损失。因此构建与研究洪水......
  • 20240813:组合计数选做
    P3214[HNOI2011]卡农题意:\(m\)个集合,\(n\)种元素,求集合间互不相同且每种元素出现偶数次的方案数。题目等价于从\(1\sim2^n-1\)里选出\(m\)个不同的数,使他们异或和为\(0\)。不妨对每个数标号,由于互不相同,最后除以\(m!\)即可。设\(f_i\)表示前\(i\)个数异或......
  • 2024年导游考试题库及答案
    1、下列有关接待宗教旅游团(者)的说法中,正确的有________。A、非穆斯林到穆斯林家中做客时,一般不主动与妇女或少女握手B、穆斯林客人禁食鳗鱼C、对基督徒可称呼弟兄、姐妹D、对佛教徒不可以道“辛苦”E、送穆斯林中国火腿答案:ABC2、导游员小张在带团过程中强迫旅游者进购......
  • 搬砖人2024年的智能工作伙伴 —— 4款思维导图软件种草集!
    幕布思维导图这玩意儿特别厉害,成了很多学生学习的好帮手,在学习中经常觉得信息太多太乱,不好理清楚。这时候用幕布思维导图,我们可以把那些复杂的知识点整理得有条有理。每个主题、每个小点都清清楚楚,学习的时候一眼就能看出重点。这种一看就明白的学习法,不仅让我们学得更快,还能让......