Skip to content

Commit

Permalink
add: contest weekly 389&390, biweekly 127
Browse files Browse the repository at this point in the history
  • Loading branch information
binacs committed Jul 21, 2024
1 parent 52a6e2d commit 65f53f6
Show file tree
Hide file tree
Showing 4 changed files with 452 additions and 0 deletions.
111 changes: 111 additions & 0 deletions basic/greedy.md
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,117 @@ public:

* * *

> [!NOTE] **[LeetCode 3085. 成为 K 特殊字符串需要删除的最少字符数](https://leetcode.cn/problems/minimum-deletions-to-make-string-k-special/)**
>
> 题意: TODO

> [!TIP] **思路**
>
> 重在理解贪心推导思路
>
> 1. 一个非常显然的思路是直接枚举最终收敛的数值区间
>
> 2. 贪心推理:下界 (而非上界) 必然出现在所有 cnt 中
>
> 思考推理 (因为如果下界处在中间位置,对于更大的区间来说向下收缩是没有意义的)
>
> 进而,在数据范围更大时可以双指针进一步优化 (略)

<details>
<summary>详细代码</summary>
<!-- tabs:start -->

##### **C++ bf**

```cpp
class Solution {
public:
int minimumDeletions(string word, int k) {
int n = word.size();
vector<int> xs;
{
int c[26];
memset(c, 0, sizeof c);
for (auto x : word)
c[x - 'a'] ++ ;

for (int i = 0; i < 26; ++ i )
if (c[i])
xs.push_back(c[i]);
sort(xs.begin(), xs.end());
}

int m = xs.size();

int res = n;
for (int i = 1; i <= 1e5 + 1; ++ i ) {
int r = i, l = max(0, r - k);

int t = 0;
for (auto x : xs)
if (x < l)
t += x;
else if (x > r)
t += x - r;
res = min(res, t);
}
return res;
}
};
```
##### **C++ gready**
```cpp
class Solution {
public:
int minimumDeletions(string word, int k) {
int n = word.size();
vector<int> xs;
{
int c[26];
memset(c, 0, sizeof c);
for (auto x : word)
c[x - 'a'] ++ ;
for (int i = 0; i < 26; ++ i )
if (c[i])
xs.push_back(c[i]);
sort(xs.begin(), xs.end());
}
int m = xs.size();
int res = n;
for (auto x : xs) {
int l = x, r = x + k;
int t = 0;
for (auto v : xs)
if (v < l)
t += v;
else if (v > r)
t += v - r;
res = min(res, t);
}
return res;
}
};
```

##### **Python**

```python

```

<!-- tabs:end -->
</details>

<br>

* * *

### 排序不等式

> [!NOTE] **[AcWing 1395. 产品处理](https://www.acwing.com/problem/content/1397/)**
Expand Down
92 changes: 92 additions & 0 deletions dp/misc.md
Original file line number Diff line number Diff line change
Expand Up @@ -1246,4 +1246,96 @@ int main() {

<br>

* * *

### 状态转移方式

> [!NOTE] **[LeetCode 3098. 求出所有子序列的能量和](https://leetcode.cn/problems/find-the-sum-of-subsequence-powers/)** [TAG]
>
> 题意: TODO
> [!TIP] **思路**
>
> 如果将所有差值离散化 统一求复杂度会爆掉 前缀和优化也无效
>
> 考虑随用随算
> 1. 借助 trick 的转移方式实现
>
> 2. 更 general 的前后缀分解,计算过程必须正确消除不可行情况
>
> 解决办法 => 必须包含边界值 => **求差值+初始化(只有边界值=1)**
>
> 重复做
<details>
<summary>详细代码</summary>
<!-- tabs:start -->

##### **C++**

```cpp
class Solution {
public:
// 长度等于k...
// 1. 排序 显然不影响结果
// 2. 枚举差值发生的两个下标对 则中间元素都不能被选 且两侧也存在部分不能选(以某个位置为端点 左侧差值不小于x 总共有多少种方案)
// 3. 去重.. 两侧区分对待即可 【经典思维】
//
// 长度恰好为k怎么解决? => 确定性状态 作为dp定义其中一个维度
//
// 【考虑 结合数据范围】
// ls[i][j][k] 左侧到i的位置 长度为j 差值不小于k 的所有方案数
//
// 【重要:状态转移方式 + 复杂度分析】

using LL = long long;
const static int N = 55, MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int n;
vector<int> ns;


int sumOfPowers(vector<int>& nums, int k) {
this->ns = nums;
this->n = ns.size();
sort(ns.begin(), ns.end());
unordered_map<int, LL> f[N][N]; // k 作为离散 hash
for (int i = 1; i <= n; ++ i ) {
f[i][1][INF] = 1;
for (int j = 2; j <= k; ++ j )
// ATTENTION 第三维并非枚举所有差值可能,而是只枚举一定可能出现的,也即枚举前面的数字
for (int last = 1; last < i; ++ last ) {
// ATTENTION trick
for (auto & [d, cnt] : f[last][j - 1]) {
LL nd = min(d, ns[i - 1] - ns[last - 1]); // trick
f[i][j][nd] = (f[i][j][nd] + cnt) % MOD;
}
}
}

LL res = 0;
for (int i = 1; i <= n; ++ i )
for (auto & [d, cnt] : f[i][k])
res = (res + d * cnt % MOD) % MOD;

return res;
}
};
```

##### **Python**

```python

```

<!-- tabs:end -->
</details>

<br>

* * *
108 changes: 108 additions & 0 deletions string/trie.md
Original file line number Diff line number Diff line change
Expand Up @@ -2116,6 +2116,114 @@ public:

* * *

> [!NOTE] **[LeetCode 3093. 最长公共后缀查询](https://leetcode.cn/problems/longest-common-suffix-queries/)**
>
> 题意: TODO

> [!TIP] **思路**
>
> 显然是 trie 核心在于压缩空间
>
> => 要想到 **考虑偏序性质 可以直接在插入时维护**

<details>
<summary>详细代码</summary>
<!-- tabs:start -->

##### **C++**

```cpp
const static int N = 1e4 + 10, M = 5e5 + 10;
int t[N];

struct Node {
Node * child[26];
int p;
Node() {
for (int i = 0; i < 26; ++ i )
child[i] = nullptr;
p = -1;
}
} *root;

Node * rs[M];
int tot;
Node * prep(int idx) {
rs[idx] = new Node();
return rs[idx];
}

class Solution {
public:
void init() {
root = new Node();
tot = 0;
}
void compare(Node * p, int i) {
// ATTENTION: 考虑严格偏序性质 可以直接在插入的时候 O(1) 维护... 不需要集合or每次全量sort
// 进而压缩空间避免MLE
int a = p->p, b = i;
if (a == -1 || (ws[a].size() > ws[b].size() || ws[a].size() == ws[b].size() && a > b))
p->p = b;
}
void insert(int i, string & w) {
auto p = root;
compare(p, i);
for (auto c : w) {
int u = c - 'a';
if (!p->child[u])
p->child[u] = prep(tot ++ );
p = p->child[u];
compare(p, i); // ATTENTION
}
}
int query(string & w) {
auto p = root;
for (auto c : w) {
int u = c - 'a';
if (!p->child[u])
break;
p = p->child[u];
}
return p->p;
}

vector<string> ws;

vector<int> stringIndices(vector<string>& wordsContainer, vector<string>& wordsQuery) {
init();

this->ws = wordsContainer;

for (int i = 0; i < ws.size(); ++ i ) {
auto & w = ws[i];
reverse(w.begin(), w.end());
insert(i, w);
}

vector<int> res;
for (auto & w : wordsQuery) {
reverse(w.begin(), w.end());
res.push_back(query(w));
}
return res;
}
};
```

##### **Python**

```python

```

<!-- tabs:end -->
</details>

<br>

* * *

### 离线 trie

> [!NOTE] **[LeetCode 1707. 与数组中元素的最大异或值](https://leetcode.cn/problems/maximum-xor-with-an-element-from-array/)**
Expand Down
Loading

0 comments on commit 65f53f6

Please sign in to comment.