• 好多句话题解


    AGC040F

    咕咕咕了好久终于编出来了
    首先看成在坐标系上面走。
    假设当前在 ((x,y)),强制 (xge y),要走到 ((A,B)),每一次可以进行下面几种操作。

    1. 走到 ((x+1,y))
    2. 如果 (x>y+1),那么可以走到 ((x,y+1))
    3. 走到 ((x,x))

    不难发现 (1) 操作一定会进行 (A) 次,只需要在操作序列上面插入 (2,3) 操作即可。
    那就枚举 (2) 操作的次数 (i) 进行计数。
    发现 (3) 操作可以看成当前的点不动,平移当前终点在的直线和终点,形成一个新的限制。
    由于我语文不是很好,所以画了一个图,大家可以简单看看。

    大概说的就是把黑线和 (T) 移动至绿线和 (T'),并把原路线跟着做一个变换。
    观察移动直线的性质:

    1. 移动后 (T'=(A',B')) 满足 (A'=A,(A'-B')-(x-y)=A-B),解出来就是 ((A,B-(x-y)))
    2. 在之后的行动中进行操作 (2) 时,必须满足不走到平移后的线。
    3. 每次直线的截距减小。

    假设没有进行 (3) 操作,那可以直接算方案数。
    假设进行了至少一次 (3) 操作,那对于每一条路径,最后一定移到 ((A,i)),且如果时间倒流,可以依次移到 ((A,i),(A,i+1)...(A,B)),于是可以插板法算插入方案数,这题就做完了。

    Code:

    inline int Cal(int n, int m) { return dec(C(n + m, n), C(n + m, n + 1)); }
    int main() {
      cin >> n >> B >> A, init_fac(n << 1);
      if (!A) return cout << 1, 0;
      int res = 0;
      for (ri j, i = 0, k; i <= B && i <= n - A; ++i) {
        int t = Cal(A - 1, i);
        if (i + A == n) Add(res, i == B ? t : 0);
        else {
          j = n - A - i - 1, k = B - i + 1;
          Add(res, mul(t, C(j + k - 1, k - 1)));
        }
      }
      cout << res;
      return 0;
    }
    

    完全背包问题

    有容量为 (m) 的背包和 (n) 种物品,每种物品的体积为 (v_i),价值为 (b_i),求体积限制内最大价值。
    (nle10^6,mle10^9,a_i,b_ile100)

    考虑转化成两个较小的子问题,假设是 (x)(m-x) 以内的完全背包问题,那么显然会有 (xle m-x,(m-x)-xle max{v_i})
    于是只需求体积限制 (limVin [frac{m-x}2,frac{m+mx}2]) 内的完全背包问题。
    这个继续按照边界拆成两个较小的,每拆一次区间的端点值都减了一半左右,且显然区间长度最后是不会超过 (2*max{v_i}) 的。
    这样拆下去,最后只需要做一个小范围(大概是 (max{v_i}*3) 这个范围内)的完全背包,然后倒着往上推就行了。
    然后由于 (a_i,b_i) 范围都是 (100),所以 (n) 是个假的,离散化一下即可。

    Code:

    const int N = 305;
    ll ori[N], f[55][N];
    int n, m, V = 0, L[55], R[55], sig = 0, tot = 0;
    pii a[N * N];
    int main() {
      m = read(), n = read();
      for (ri i = 1; i <= n; ++i) {
        ++sig;
        a[sig].fi = read(), a[sig].se = read();
        ckmax(V, a[sig].fi);
      }
      sort(a + 1, a + sig + 1), sig = unique(a + 1, a + sig + 1) - a - 1;
      int S1 = m, S2 = m;
      while (S1 > 0) L[++tot] = S1, R[tot] = S2, S1 = (S1 - V) / 2, S2 = (S2 + V) / 2;
      for (ri i = 1; i <= sig; ++i) for (ri j = a[i].fi; j <= V * 3; ++j) ckmax(ori[j], ori[j - a[i].fi] + a[i].se);
      for (ri i = tot; i; --i) {
        for (ll v = L[i]; v <= R[i]; ++v) {
          if (v <= V * 3) f[i][v - L[i]] = ori[v];
          else for (ll j = (v - V) / 2; j <= v / 2; ++j)
          ckmax(f[i][v - L[i]], f[i + 1][j - L[i + 1]] + f[i + 1][v - j - L[i + 1]]);
        }
      }
      cout << "max=" << f[1][0];
      return 0;
    }
    
  • 相关阅读:
    《经济学通识》六、生命有限
    《经济学通识》五、反垄断的罪与罚
    《经济学通识》四、贸易与互惠
    《经济学通识》三、价格与市场
    《经济学通识》二、管制的愿望与结果
    《经济学通识》一、前言
    《必然》十三、开始,正从脚下开始
    《必然》十二、一个好问题足以改变世界
    字符串之strstr
    STL之内存处理工具
  • 原文地址:https://www.cnblogs.com/ldxcaicai/p/13326532.html
Copyright © 2020-2023  润新知