「LibreOJ β Round #2」贪心只能过样例

知识点: bitset,01 背包

原题面 Loj


题意简述

给定 \(n\) 个数,\(x_i\) 的取值范围 \([a_i,b_i]\)
求不同的 \(\sum\limits_{i=1}^{n}x_{i}^{2}\) 的种类数。
\(1\le n,a_i,b_i\le 100\)


分析题意

数据范围比较喜人,\(\sum x_i^2\) 的值域较小,考虑一波暴力。
开 n 个 vector,记录 \(1\sim i\) 能组成的所有数。
对于第 \(i+1\) 个数,枚举 \(1\sim i\) 能组成的所有数进行转移,可以写出下面的暴力代码。
\(n,a_i,b_i\) 同阶,复杂度是 \(O(n^4)\) 级别。


发现这个转移很像 01 背包的转移,加之值域较小。
考虑直接用 01 背包求能组成哪些数。

\(f_{i,j} = (0/1)\) 表示当前枚举到第 \(i\) 个数,能否通过 \(1\sim i\) ,组成 \(j\)
有状态转移方程:

\[f_{i,j} = [\exist x\in [a_i,b_i],[f_{i-1,j-x^2}]] \]

01 背包倒序枚举消去第一维,复杂度 \(O(n^2)\) 级别。


发现用个桶判定出现这里好傻逼啊,考虑用 bitset 进行维护。
转移与上述 01 背包的方法本质相同,直接右移或起来即可。


代码实现

正解

//知识点:bitset 
/*
By:Luckyblock
*/
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <bitset>
#define ll long long
const int kMaxn = 110;
//=============================================================
int n;
std :: bitset <kMaxn * kMaxn * kMaxn> vis[kMaxn];
//=============================================================
inline int read() {
  int f = 1, w = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir_, int sec_) {
  if (sec_ > fir_) fir_ = sec_;
}
void GetMin(int &fir_, int sec_) {
  if (sec_ < fir_) fir_ = sec_;
}
//=============================================================
int main() {
  n = read();
  vis[0][0] = true;
  for (int i = 1; i <= n; ++ i) {
    int a = read(), b = read();
    for (int j = a; j <= b; ++ j) {
      vis[i] |= (vis[i - 1] << (j * j));
    }
  }
  printf("%d\n", vis[n].count());
  return 0;
}

暴力

//傻逼暴力/cy
//判定出现这里好傻逼啊,改成bitset试试 
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <vector>
#define ll long long
const int kMaxn = 110;
//=============================================================
int n;
bool vis[kMaxn][kMaxn * kMaxn * kMaxn];
std :: vector <int> ans;
//=============================================================
inline int read() {
  int f = 1, w = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir_, int sec_) {
  if (sec_ > fir_) fir_ = sec_;
}
void GetMin(int &fir_, int sec_) {
  if (sec_ < fir_) fir_ = sec_;
}
//=============================================================
int main() {
  n = read();
  ans.push_back(0);
  for (int i = 1; i <= n; ++ i) {
    int a = read(), b = read();
    std :: vector <int> tmp;
    for (int j = a; j <= b; ++ j) {
      int x = j * j;
      for (int k = 0, size = ans.size(); k < size; ++ k) {
        int now = ans[k] + x;
        if (! vis[i][ans[k] + x]) {
          vis[i][ans[k] + x] = true;
          tmp.push_back(ans[k] + x);
        }
      }
    }
    ans.clear();
    for (int k = 0, size = tmp.size(); k < size; ++ k) {
      ans.push_back(tmp[k]);
    }
  }
  printf("%d\n", ans.size());
  return 0;
}
posted @ 2020-09-02 20:22  Luckyblock  阅读(220)  评论(0编辑  收藏  举报