柿子饼同学 发表于 2024-8-21 22:23:15

[心之碎片] - 20240817模拟赛

总结与反思
B - 对于求权值总和 / 乘积 等于定值要想到背包dp
C - sgt 维护的值看看是否冗余, 只需要单点修改的东西不需要进入 up 和 dn


B - ppip 数列
ppip看到了一个各元素均为正整数、长度为k、各元素之和为n的不降数列。
他想要知道这种数列的个数,对998244853取模。

转化为 权值为 1 - k 的物品, 不限制取的个数, 总和为 n 的方案数, 转化为完全背包问题

在遇到【不易处理的限制】与【就算有限制也很好处理,可惜没限制】的问题时,可以通过转转转将其转化。
原本横向的性质,在新问题上必须纵向考虑。
对于有关【整数】、【重复】等的问题,可考虑将【有无】与【数量之差】相互转化。
f = 1;
    cin >> n >> k;
    n -= k;

    for (int i = 1; i <= k; i++) {
      for (int j = i; j <= n; j++) {
            f = (f + f) % P;
      }
    }

    cout << f;

D - P4472 八维
倍增, 哈希
#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ll;
typedef pair<int, int> pii;

const int N = 505;
const ll B = 233;
const int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};

char s;
int n, m, K;
ll p, f;
long long same, all;
pii g;
unordered_map<ll, int> cnt;

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m >> K;
    for(int i = 0; i < n; i++){
      cin >> s;
    }

    int lim = log2(K);
    p = B;
    for(int i = 1; i <= lim; i++){
      p = p*p;
    }

    for(int d = 0; d < 8; d++){
      // 录入 f, g
      for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                f = s;
                g = make_pair((i + dx + n) % n, (j + dy + m) % m);
            }
      }

      // 倍增
      for(int k = 1; k <= lim; k++){
            for(int i = 0; i < n; i++){
                for(int j = 0; j < m; j++){
                  int x = g.first;
                  int y = g.second;

                  f = f*p + f;
                  g = g;
                }
            }
      }

      for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                ll hash = 0;
                auto cur = make_pair(i, j);

                for(int k = lim; k >= 0; k--){
                  if((K >> k) & 1){
                        hash = hash*p + f;
                        cur = g;
                  }
                }

                cnt++;
            }
      }
    }

    for(auto v : cnt){
      same += 1ll*v.second*v.second;
    }
    all = 64ll*n*n*m*m;

    cout << same / __gcd(same, all) << '/' << all / __gcd(same, all);

    return 0;
}

FishC 发表于 2024-8-21 22:23:37

在这段描述中,你提到了两道题,以及你对解决方案的总结与反思。让我为你进一步简化和解释:

### B - ppip 数列

#### 问题描述:
你需要找到所有长度为k的、不降的正整数数列,这些数列的元素之和为n,并对结果进行取模运算。

#### 解题思路:
这个问题可以通过将其转换为完全背包问题来解决:
1. 视每个数列元素为背包中的物品,每个物品的权值为1到k。
2. 求权值总和为\(n - k\)的方案数。

#### 解决方法:
使用动态规划来解决背包问题。你的思路是正确的,可以通过完全背包的DP实现。

#### 示例代码:
#include <iostream>
#include <vector>
#define MOD 998244853

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    n -= k;

    vector<int> dp(n + 1, 0);
    dp = 1;

    for (int i = 1; i <= k; ++i) {
      for (int j = i; j <= n; ++j) {
            dp = (dp + dp) % MOD;
      }
    }
   
    cout << dp << endl;
    return 0;
}

### C - sgt 维护的值看看是否冗余
你提到`sgt`(线段树)需要维护的值时,需要确认是否存在冗余。对于只需要单点修改的情况,不需要进入`up`和`dn`。

### 总结:
1. **转化思路** - 对于不容易处理的复杂限制条件,可以尝试通过不同的角度(例如横向与纵向转换)来简化问题。
2. **背包问题** - 遇到求解和或积等于某定值的问题时,可以通过背包DP的方式来解决。
3. **数据结构优化** - 在使用数据结构如线段树时,确保操作的值没有冗余,优化复杂度。对于单点修改,只需要更新相关节点,不需要进行其他多余操作。

希望这些解答能帮助你更清晰地理解和解决这些问题!如果还有其他不明白的地方,随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

简柠啦 发表于 2024-8-22 08:58:28

{:10_256:}{:10_256:}

sfqxx 发表于 2024-8-22 12:31:54

666

harryhan123 发表于 2024-8-22 20:21:44

666

很cool的阳 发表于 2024-8-23 09:37:00

{:7_142:}

磷酸 发表于 2024-8-23 16:17:43

闻币而来

ooio 发表于 2024-8-23 16:22:16

{:10_256:}

曾热爱这世界 发表于 2024-8-24 11:45:56

&#128076;

zsy0226 发表于 2024-8-29 09:24:56

{:7_113:}币

trinityee 发表于 2024-9-1 10:02:20

{:10_254:}{:10_254:}看看

森林格格屋 发表于 2024-9-4 17:16:53

谢谢
页: [1]
查看完整版本: [心之碎片] - 20240817模拟赛