zoukankan      html  css  js  c++  java
  • T2695 桶哥的问题——吃桶

    题目描述

    桶哥的桶没有送完,他还有n个桶。他决定把这些桶吃掉。他的每一个桶两个属性:种类ai和美味值bi。若下标为x, y, z(下标从1开始)的三个桶满足:

    x<z切x+y=z-2y且ax=az     那么他们构成一个套餐,会产生(x+z)*(bx-bz)的价值

    问:一共会产生多少价值

    首先来讲暴力打法:

    最暴力的显然就是n^3的三层循环枚举了——20分

    再来说一下小小的优化:

    我们发现每个套餐所产生的价值和y没有任何关系,而且题目中x+y=z-2y的条件等价于z-x=3y,也就是说只要z-x是3的倍数就可以,所以我们可以不一个个枚举,只需要枚举(z-x)%3==0的情况就好了——40分

    接着,继续从条件入手:我们发现x和z的桶的种类是一样的,也就是说我们可以开一个vector数组来存储相同种类的桶,这样就可以进一步加快——60分

    正解:

    看到这个数据范围,基本上就是O(1)或者O(n log n)的速度了

    大体还是枚举,但是我们注意到3这个数字,对于x,一共有三种类型,即xΞ0,1,2,(mod 3),也就是说我们不用一个一个判断,可以直接枚举同余的情况

    我们可以把(x+z)*(bx-bz)这个式子拆开:xbx-xbz+zbx-zbz,发现当你枚举了x,再枚举z时,x是不变的,bx也是不变的,所以我们可以用前缀和来存储这些东西

    如果变成求和:Σx bx-Σx bz+z Σbx-zbzΣ1

    再进一步,我们发现对于每一个枚举的x和z,他们的价值都可以用前缀和来表示,那么我们就把双层枚举变为了一层枚举

    代码:

    #include <algorithm>
    #include <cctype>
    #include <cstdio>
    #include <cstring>
    
    int readInt() {
      int ans = 0, c, f = 1;
      while (!isdigit(c = getchar()))
        if (c == '-') f *= -1;
      do ans = ans * 10 + c - '0';
      while (isdigit(c = getchar()));
      return ans * f;
    }
    
    const int mod = 10007;
    
    int b[100005], a[100005];
    int S[100005], Sx[100005], Sbx[100005], Sxbx[100005];
    
    int main() {
      int n = readInt(); /* m = */readInt();
      for(int i = 1; i <= n; i++) b[i] = readInt() % mod;//美味值 
      for(int i = 1; i <= n; i++) a[i] = readInt();//种类 
      int ans = 0;
      for (int cc = 1; cc <= 3; ++cc) {
        // { cc, cc+3, cc+6 ... } 分一组
        memset(S, 0, sizeof(S));
        memset(Sx, 0, sizeof(Sx));
        memset(Sbx, 0, sizeof(Sbx));
        memset(Sxbx, 0, sizeof(Sxbx));
        for(int i = cc; i <= n; i += 3) {
          ans = (ans + i % mod * Sbx[a[i]] % mod) % mod;
          ans = (ans - b[i] * Sx[a[i]] % mod) % mod;
          ans = (ans + Sxbx[a[i]]) % mod;
          ans = (ans - S[a[i]] * b[i] % mod * (i % mod) % mod) % mod;
          //Σx bx - Σx bz + z Σbx - zbz Σ1
          Sbx[a[i]] = (Sbx[a[i]] + b[i]) % mod;//Σbx
          Sx[a[i]] = (Sx[a[i]] + i) % mod;//Σx
          Sxbx[a[i]] = (Sxbx[a[i]] + i % mod * b[i] % mod) % mod;//Σbx
          S[a[i]] = (S[a[i]] + 1) % mod;//Σ1
        }
      }
      printf("%d", (ans + mod) % mod);
      return 0;
    }
  • 相关阅读:
    python
    python
    python
    python
    python
    python-接口自动化 token 的处理
    如何顺利度过试用期?
    印象深刻-bug汇总
    go 实现1000以内的数字,输入35 输出三十五
    jenkins 汉化
  • 原文地址:https://www.cnblogs.com/lcezych/p/10939826.html
Copyright © 2011-2022 走看看