首页 > 其他分享 >20241108

20241108

时间:2024-11-08 22:19:47浏览次数:3  
标签:20241108 int 4005 long 括号 405 include

T1

小鸣的疑惑

观察发现第一项贡献恒正,第二项贡献恒负,第三项贡献为 \(0\),并且一项的贡献与后面无关。于是套用对第三项的分析会发现从第三项往后的所有东西贡献都是 \(0\)。于是答案为 \(a_1 - a_2\)。

代码
#include <iostream>
#define int long long
using namespace std;
const int P = 998244353;
int n;
int a[100005];
signed main() {
    freopen("aminusb.in", "r", stdin);
    freopen("aminusb.out", "w", stdout);
    int tc;
    cin >> tc;
    while (tc--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
        cout << (a[1] - a[2] + P) % P << "\n";
    }
    return 0;
}

T2

红蔷薇白玫瑰

dfs 枚举答案,只需要判断走到当前点的路径的后 \(m\) 位是否和给定串匹配即可。哈希或 kmp 自动机或 AC 自动机都能做。

代码
#include <iostream>
#define int long long
using namespace std;
const int B = 2333;
const int P = 1610612741;
int ls[300005], rs[300005], ans[300005];
int n, m, hm1, hm2, pw1, pw2;
unsigned long long h1[300005];
int h2[300005], stk[300005];
void dfs(int x, int d) {
    stk[d] = x;
    if (d > m) {
        if (h1[d] - h1[d - m] * pw1 == hm1 && (h2[d] - h2[d - m] * pw2 % P + P) % P == hm2) 
            ans[stk[d - m]] = x;
    }
    if (ls[x]) {
        h1[d + 1] = h1[d] * B + 1;
        h2[d + 1] = (h2[d] * B + 1) % P;
        dfs(ls[x], d + 1);
    }
    if (rs[x]) {
        h1[d + 1] = h1[d] * B + 2;
        h2[d + 1] = (h2[d] * B + 2) % P;
        dfs(rs[x], d + 1);
    }
}
signed main() {
    freopen("rose.in", "r", stdin);
    freopen("rose.out", "w", stdout);
    cin >> n;
    for (int i = 1; i < n; i++) {
        int u, w, v;
        cin >> u >> v >> w;
        w ? (rs[u] = v) : (ls[u] = v);
    }
    cin >> m;
    for (int i = pw1 = pw2 = 1, x; i <= m; i++) {
        cin >> x;
        hm1 = hm1 * B + x + 1;
        hm2 = (hm2 * B + x + 1) % P;
        pw1 = pw1 * B;
        pw2 = pw2 * B % P;
    }
    dfs(1, 1);
    for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
    cout << "\n";
    return 0;
}

T3

山遥路远

考虑判断括号串,第一种方法是从前往后扫并记录当前左括号个数。套到这个题一看就非常扯淡,因为你就算能知道左括号最多有多少这个做法所需要的 dp 的状态数也是不能在套了一个 dijkstra 之后通过的,没有前途。我们考虑区间 dp 判断括号串。设 \(f[x][y]\) 表示从 \(x\) 到 \(y\) 中间构成合法括号串的最小长度。然后转移只需要考虑把两个拼起来和在两边各拼一个。这个做法转移简单,状态数少,简直不能更有前途一点了。我们考虑直接在这个做法上套 dijkstra,每次取出堆顶的时候直接枚举在当前串后面拼的合法括号串是从 \(y\) 到哪个点,以及要从哪个点拼一个合法括号串到 \(x\)。对于前后各拼一个我们直接做分步转移,有辅助状态 \(g[x][y]\) 表示目前 \(x \rightarrow y\) 去掉第一个字符(左括号)就是合法括号序列的最小长度,然后两个 dp 用一个 dijkstra 一块转移就没了。

代码
#include <iostream>
#include <string.h>
#include <vector>
#include <queue>
#define int long long
using namespace std;
const int P = 998244353;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, m, qs;
int f[405][405], g[405][405];
bool vis[2][405][405];
struct node {
    int t, x, y, dis;
};
vector<pair<int, int> > G1[405], G2[405];
inline bool operator<(node a, node b) { return a.dis > b.dis; }
priority_queue<node> q;
void dijkstra() {
    for (int i = 1; i <= n; i++) q.push((node) { 0, i, i, f[i][i] = 0 });
    while (!q.empty()) {
        node tmp = q.top();
        q.pop();
        int x = tmp.x, y = tmp.y, t = tmp.t;
        if (vis[t][x][y]) 
            continue;
        vis[t][x][y] = 1;
        if (t) {
            for (auto p : G1[y]) {
                int v = p.first;
                if (f[x][v] > g[x][y] + p.second) 
                    q.push((node) { 0, x, v, f[x][v] = g[x][y] + p.second });
            }
        } else {
            for (auto p : G2[x]) {
                int v = p.first;
                if (g[v][y] > f[x][y] + p.second) 
                    q.push((node) { 1, v, y, g[v][y] = f[x][y] + p.second });
            }
            for (int i = 1; i <= n; i++) {
                if (f[x][i] > f[x][y] + f[y][i]) 
                    q.push((node) { 0, x, i, f[x][i] = f[x][y] + f[y][i] });
            }
            for (int i = 1; i <= n; i++) {
                if (f[i][y] > f[x][y] + f[i][x]) 
                    q.push((node) { 0, i, y, f[i][y] = f[i][x] + f[x][y] });
            }
        }
    }
}
signed main() {
    freopen("distant.in", "r", stdin);
    freopen("distant.out", "w", stdout);
    memset(f, 63, sizeof f);
    memset(g, 63, sizeof g);
    cin >> n >> m >> qs;
    for (int i = 1; i <= m; i++) {
        int u, v, ww, t;
        cin >> u >> v >> ww >> t;
        (t & 1) ? G2[v].emplace_back(make_pair(u, ww)) : G1[u].emplace_back(make_pair(v, ww));
    }
    dijkstra();
    for (int i = 1, s, t; i <= qs; i++) {
        cin >> s >> t;
        cout << (f[s][t] == inf ? -1 : f[s][t]) % P << "\n";
    }
    return 0;
}

T4

命运歧途

首先考虑以子集反演为基础的容斥,由于对于一个钦定的非法(间隔)位置集合,没有被钦定的(间隔)位置会将序列分成若干段。我们只关心段的数量,所以只需要考虑钦定了多少非法位置。注意到每一段中都是公差为 \(k\) 的等差数列,因此考虑按照模 \(k\) 的余数将所有数分组。由于每个等差数列可以是增的也可以是减的,所以每个长度不为 \(1\) 的段有两种方案。那么现在相当于我们有若干个组,每组是一个数列,要求出将所有数列分段,一共分出来 \(x\) 段的方案数。在组之间我们直接背包合并,则只需要求出将 \(i\) 个数分 \(j\) 段的方案数。这个是容易前缀和优化到 \(\mathcal{O}(n^2)\) 的。然后每次询问就直接背包合并,这个复杂度就是 \(\mathcal{O}(qn^2)\) 的。然后考虑优化,发现对于每个 \(k\) 我们分的组的大小是 \(\lfloor \frac{n}{K} \rfloor\) 和 \(\lfloor \frac{n}{K} \rfloor + 1\) ,而这个东西的取值只有根号种。因此对每个这个东西的取值计算,就分成根号个块。容易发现块内分出的两种的个数都是单调的,于是可以类似莫队维护两个单调的指针每次移动。然后使用暴力多项式乘除就可以做到 \(\mathcal{O}(n^{2.5})\)。这里的多项式除法由于被除式的最高次项的系数一定是 \(1\),所以直接除即可。

代码
#include <iostream>
#include <string.h>
#define int long long
using namespace std;
int n, q, P;
inline void Madd(int& x, int y) { (x += y) >= P ? (x -= P) : 0; }
int pre[4005][4005];
int f[4005][4005]; // i numbers, j segments
int F[4005], G[4005];
int fac[4005], ans[4005];
void Add(int x, int deg) {
    for (int i = 0; i <= deg; i++) G[i] = F[i];
    for (int i = deg; ~i; i--) {
        if (F[i]) {
            for (int j = 1; j <= x; j++) {
                if (f[x][j]) 
                    Madd(F[i + j], 1ll * F[i] * f[x][j] % P);
            }
        }
    }
    for (int i = 0; i <= deg; i++) Madd(F[i], P - G[i]);
}
void Del(int x, int deg) {
    for (int i = deg, v; i >= x; i--) {
        v = G[i - x] = F[i];
        for (int j = 0; j <= x; j++) 
            Madd(F[i - j], P - 1ll * v * f[x][x - j] % P);
    }
    memset(F, 0, sizeof F);
    for (int i = 0; i <= deg - x; i++) F[i] = G[i];
}
signed main() {
    freopen("fate.in", "r", stdin);
    freopen("fate.out", "w", stdout);
    cin >> n >> q >> P;
    fac[0] = f[0][0] = 1;
    for (int i = 0; i <= n; i++) pre[0][i] = 1;
    for (int i = 1; i <= n; i++) {
        fac[i] = 1ll * fac[i - 1] * i % P;
        for (int j = f[i][i] = pre[i][i] = 1; j <= n; j++) {
            f[i][j] = (pre[i - 1][j - 1] + (j > 1 ? pre[i - 1][j - 2] : 0)) % P;
            pre[i][j] = (pre[i][j - 1] + f[i][j]) % P;
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= i; j++) 
            swap(f[i][j], f[j][i]);
    }
    int cur = 0;
    for (int K = 1, m1, m2, c1, c2; K <= n; K++) {
        if (K == 1 || n / K != n / (K - 1)) {
            m1 = n / K, m2 = n / K + 1;
            c1 = K - n % K, c2 = n % K;
            memset(F, 0, sizeof F);
            F[cur = 0] = 1;
            for (int i = 1; i <= c1; i++) Add(m1, cur += m1);
            for (int i = 1; i <= c2; i++) Add(m2, cur += m2);
        } else {
            while (c1 > K - n % K) Del(m1, cur), cur -= m1, --c1;
            while (c1 < K - n % K) Add(m1, cur), cur += m1, ++c1;
            while (c2 < n % K) Add(m2, cur), cur += m2, ++c2;
            while (c2 > n % K) Del(m2, cur), cur -= m2, --c2;
        }
        for (int i = 0; i < n; i++) i & 1 ? Madd(ans[K], P - 1ll * F[n - i] * fac[n - i] % P) : Madd(ans[K], 1ll * F[n - i] * fac[n - i] % P);
    }
    while (q--) {
        int x;
        cin >> x;
        cout << ans[x] << "\n";
    }
    return 0;
}

前两题花的时间有点长,这是不好的。

T3 一直在想记录左括号数量的 dp,无法优化,后来想到正解却以为只能在 DAG 上做。不好评价了。

T4 一直没有把两边都不是非法位置的位置视为独立段,就一直不会 dp。唐了。

标签:20241108,int,4005,long,括号,405,include
From: https://www.cnblogs.com/forgotmyhandle/p/18536040

相关文章

  • [20241108]跟踪library cache lock library cache pin使用gdb(11g)4.txt
    [20241108]跟踪librarycachelocklibrarycachepin使用gdb(11g)4.txt--//验证前面建立的gdb脚本确定librarycachepinaddress是否正确.1.环境:SCOTT@book>@ver1PORT_STRING                   VERSION       BANNER---------------------------......
  • [20241108]跟踪library cache lock library cache pin使用gdb(11g)3.txt
    [20241108]跟踪librarycachelocklibrarycachepin使用gdb(11g)3.txt--//前一段时间写的使用gdb跟踪librarycachelock/librarycachepin的脚本。--//我看过以前的笔记,当时测试过链接https://nenadnoveljic.com/blog/library-cache-lock-debugger/,我的测试在11g是失败.--//......