首页 > 其他分享 >闲话 22.10.28

闲话 22.10.28

时间:2022-10-28 18:56:33浏览次数:69  
标签:cnt frac int 闲话 质数 28 22.10 rep mod

闲话

明日CSP,而我连廊桥都不会分配
我是不是要抱泠了

于是今日晚上写一些板子

480p
soytony:斯大林p
这是什么新p主能不能各位给我科普一下

今日歌词是摘了美影日记里新的那部分!
今天推的歌是美影日记!希望各位能去看看新的pv

雨のち曇り晴れ

優しくきっと晴れ

きらきら浮かぶ言葉

もう忘れちゃうけれど

杂题

给定两个整数 \(n, m\) 和两个字符串 \(w_1, w_2\)。\(n\) 是两个字符串的长度,\(m\) 是答案 \(P\) 的下界,\(n, m \le {10}^5\)。

定义 Hash 函数如下

\[H_p(w)=\sum_{i=0}^{|w|-1}w_ir^i\bmod P \]

其中 \(P\) 是一个质数。

请你寻找任意一对 \(P,r\) 满足 \(H_p(w_1)=H_p(w_2)\),题目保证至少存在一组可行解。

\(m\leqslant P\leqslant 10^9\),\(2\leqslant r\leqslant P-2\)。

仍然是翻译的官方题解。

问题可以被简单陈述如下:给定一个整系数多项式 \(f(x) = \sum_{i=0}^{n-1} f_ix^i\),找到一个大质数 \(p\) 以及 \(r \in [2, p-2]\) 使得 \(f(r) \equiv 0 \pmod p\)。

一种解法是随机找到一个质数 \(p\),并依次检查所有 \(r\) 的取值。由于对于 \(r\) 的随机值来说 \(f(r) \text{ mod } p\) 也可以被认为是随机的,因此我们可以粗略地认为所有 \(r\) 都不满足要求的概率为

\[\left(1-\frac 1p\right)^p \approx e^{-1} \ge \frac 13 \]

因此我们只需重复 \(O(1)\) 次质数的选取。使用多项式多点求值能做到大常数的 \(O(n \log^2 n)\)。这足以解决问题,但这不是最优秀的做法,也不是最优雅的方法 : )

下面将讲述另一种做法。我们令 \(d\) 为 \(p-1\) 的任意因子。众所周知,在模 \(p\) 整数域内有恰好 \(d\) 个元素 \(r\) 满足

\[r^d \equiv 1 \pmod p \]

注意到如果 \(r\) 是这样一个元素,则以 \(d=3\) 为例,有

\[r^{10} + r^5 \equiv r^{3\times 3 + 1} + r^{3+2} \equiv (r^3)^3 \times r + r^3\times r^2\equiv r +r^2 \pmod p \]

事实上,如果我们将这一性质应用到整个多项式上,我们就可以将同余项的系数合并,得到一个更小度数的多项式

\[f^{(d)}(r) = \sum_{i=0}^{d-1}\alpha_ir^i \]

这样求 \(d\) 个点只需要 \(O(d^2)\) 的复杂度。

当前算法的过程如下:寻找一个小整数 \(d\),选择一个形如 \(kd+1\) 的质数 \(p > m\),随后找到所有满足 \(r^d \equiv 1\pmod p\) 的整数 \(r\),随后对这些位置求解 \(f^{(d)}(r)\) 的值,祈祷着得到的值是 \(0\)。
决定性的 trick 就是既然 \(f^{(d)}\) 的系数能被一劳永逸地算出来,我们就可以对大量质数分别在 \(O(d^2)\) 的复杂度内计算所有的 \(r\) 位置对应的值。
注意到,如果我们还相信 \(f^{(d)} \pmod p\) 的值是随机的(而且我们必须要相信),那大致上 \(\frac md\approx \frac {10^5}d\) 个质数就应当足够了。

还剩下两个问题:1. 我们该选什么样的数 \(d\)? 2. 我们该如何找到满足 \(r^d \equiv 1 \pmod p\) 的整数 \(r\)?
对于 1. ,我们发现最好的选择就是那些小质数,例如 \(3,5,7,11,\cdots\)。这样我们就能留下大量形如 \(kd+1\) 的质数 \(p\),而且 \(O(d^2)\) 的时间复杂度开销也不会很大。
对于 2. ,当选好了 \(d\) 后找到满足如上条件的整数 \(r\) 也不是很难。我们随机一个整数 \(r_0\),取 \(r_0^{\frac{p-1}d}\) 为对应整数。正确性考虑费马小定理。这一步实际选出并在之后使用的数是 \(r_0^{\frac{p-1}d}\),因此其不可等于 \(1\)。

具体地说,以下流程的算法跑得很好:

  1. 选择一个质数 \(d\) 以及一个质数 \(p = kd+1\)。
  2. 从 \(r\in \{1, 2, \dots, p-1\}\) 中随机抽取一个值。
  3. 若 \(r^{\frac {p-1} d} \neq 1\) 进入下一步,反之回到上一步。
  4. 计算模 \(p\) 意义下的 \(f^{(d)}(r), f^{(d)}(r^2),\dots f^{(d)}(r^d)\)。

可以证明,上述算法一定能够输出我们想要的答案。进一步的,由于每个 \(d\) 会产生 \(O(\frac md)\) 个质数 \(p\),每个质数 \(p\) 能够验证 \(O(d^2)\) 个数字,因此取得 \(d\) 但无法得到所需答案的概率为

\[\left(1-\frac 1p\right)^{d^2\times \frac pd} = \left(1-\frac 1p\right)^{pd} \]

可以看到期望复杂度很优秀。

code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for (register int i = (a), i##_ = (b) + 1; i < i##_; ++i)
#define pre(i,a,b) for (register int i = (a), i##_ = (b) - 1; i > i##_; --i)
const int N = 1e6 + 10;
int n, m, str[N];
char s[N], t[N]; 
 
int prime[N], cnt; bool vis[N];
void sieve(int bnd) {
    rep(i,2,bnd) {
        if (!vis[i]) prime[++cnt] = i;
        rep(j,1,cnt) {
            if (i * prime[j] > bnd) break;
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        } 
    }
}
 
int qp(int a, int b, int mod) {
    int ret = 1;
    while (b) {
        if (b & 1) ret = 1ll * ret * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    } return ret;
}
 
int a[N];
void check(int d) {
    rep(i,0,d-1) a[i] = 0;
    rep(i,0,n) a[i % d] += str[i];
    for (int p = m / d * d + d + 1; p < 1e6; p += d) if (!vis[p]) {
        int r, r0;
        while (true) {
            r = rand() * rand() % (p - 2) + 1;
            r0 = qp(r, (p-1) / d, p); 
            if (r0 == 1) continue;
            // cout << r << ' ' << r0 << endl;
            r = r0;
            rep(tmp,1,d) {
                int t = 0, bse = 1;
                rep(i,0,d-1) t = (t + 1ll * bse * a[i]) % p, bse = 1ll * bse * r % p;
                if (t == 0) { cout << p << ' ' << r << endl; exit(0); }
                r = 1ll * r0 * r % p;
            }
            break;
        }
    }
}
 
signed main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n >> m >> s+1 >> t+1;
    rep(i,1,n) str[i] = s[i] - t[i];
    sieve(1e6);
    rep(i,2,cnt) check(prime[i]);
}



CF1276D

给定一棵\(n\)个点的树,点编号\(1 \sim n\),第\(i\)条边连接\(a_i\)和\(b_i\)。初始时你有一个空的序列,树上的\(n\)个点都有标记。现在按照边的编号从小到大考虑每一条边:

  • 如果这一条边连接的两个点都有标记,则选择其中的一个点,擦除它的标记并将它的编号放入序列的末端;

  • 否则什么都不做。

求能够由上述操作得到的不同的序列数量\(\bmod 998244353\)。

\(n \le 2\times 10^5\)

dp 题。

由于加边是有顺序的,考虑按照时间设计 dp 数组状态。

我们称一条边覆盖了一个点,当且仅当这条边擦除了这个点的标记。
然后设 \(f_{i,j}\) 为 \(i\) 节点子树的状态数,\(j\) 规定了 \(i\) 节点状态被擦除的情况。

  1. \(j=0\) 表示该节点被连向父亲的边前的连向儿子的边覆盖。
  2. \(j=1\) 表示该节点被连向父亲的边覆盖。
  3. \(j=2\) 表示该节点被连向父亲的边后的连向儿子的边覆盖。
  4. \(j=3\) 表示该节点没有被覆盖。

然后转移。

首先讨论被连向儿子的边覆盖。
枚举覆盖边连向的儿子。这个儿子 \(y\) 一定是在被连向父亲的边后被覆盖。转移值有 \(f_{y,2/3}\)。然后枚举其他儿子。对应边编号在 \(y\) 之前的点 \(z\) 一定要被覆盖,转移值有 \(f_{z,0/1}\),在 \(y\) 之后的点 \(z\) 不一定被覆盖,转移值有 $f_{z,0/2/3}。
先不考虑 \(j\) 的取值对 \(y\) 的限制,列出转移式:

\[f_{x,0/2} = \sum_{y} \left( (f_{y,2} + f_{y,3})\times \prod_{z < y} (f_{z,0} + f_{z,1}) \times \prod_{z \ge y} (f_{z,0} + f_{z,2}+f_{z,3}) \right) \]

限制自行加入。

然后讨论被父亲覆盖。
由于当前节点是被父亲覆盖的,因此其孩子中所有小于父亲的边都不能在覆盖当前节点后再覆盖。由于这条边不会删除当前节点,因此当前边只能擦除子节点。因此转移 \(f_{y,0/1}\) 。
相似的讨论说明对于大于父亲的节点不能选择 \(f_1\),因此转移 \(f_{y,0/2/3}\)。

\[f_{x,1} = \prod_{z < fa} (f_{z,0} + f_{z,1}) \times \prod_{z \ge fa} (f_{z,0} + f_{z,2}+f_{z,3}) \]

然后讨论未被覆盖。

\[f_{x,3} = \prod_{y} (f_{z,0} + f_{z,1}) \]

转移即可。

code
#include <bits/stdc++.h>
using namespace std;
#ifdef ONLINE_JUDGE
    char buf[1<<21], *p1 = buf, *p2 = buf;  inline char getc() { return (p1 == p2 and (p2 = (p1 = buf) + fread(buf, 1, 1<<21, stdin), p1 == p2) ? EOF : *p1++); }
    #define getchar getc
#endif
template <typename T> inline void get(T & u){
	u = 0; char ch = getchar(); bool f = 0; while (ch < '0' or ch > '9') f = f or ch == '-',  ch = getchar();
	while (ch >= '0' and ch <= '9') u = (u<<1) + (u<<3) + (ch^48), ch = getchar(); f and (u = -u);
} template <typename T, typename ... Args> inline void get(T & u, Args & ... _Args) { get(u); get(_Args...); }
#define rep(i,a,b) for (register int i = (a), i##_ = (b) + 1; i < i##_; ++i)
#define pre(i,a,b) for (register int i = (a), i##_ = (b) - 1; i > i##_; --i)
const int N = 5e5 + 10, mod = 998244353;
int n, t1, t2, f[N][4]; 
vector <int> g[N];

void dfs(int u, int fa) {
    for (auto v : g[u]) if (v != fa) dfs(v, u);
    static int cnt, fap, _01[N], _23[N], _023[N];
    cnt = fap = 0; _01[0] = 1;
    for (auto v : g[u]) if (v == fa) fap = cnt;
    else {
        ++cnt;
        _01[cnt] = 1ll * _01[cnt - 1] * (f[v][0] + f[v][1]) % mod;
        _23[cnt] = f[v][2] + f[v][3]; if (_23[cnt] >= mod) _23[cnt] -= mod;
        _023[cnt] = _23[cnt] + f[v][0]; if (_023[cnt] >= mod) _023[cnt] -= mod;
    } 
    _023[cnt + 1] = 1;
    pre(i,cnt - 1,1) _023[i] = 1ll * _023[i + 1] * _023[i] % mod;
    rep(i,1,cnt) 
        if (i <= fap) f[u][0] = (f[u][0] + 1ll * _01[i - 1] * _23[i] % mod * _023[i + 1]) % mod;
        else f[u][2] = (f[u][2] + 1ll * _01[i - 1] * _23[i] % mod * _023[i + 1]) % mod;
    f[u][1] = 1ll * _01[fap] * _023[fap + 1] % mod;
    f[u][3] = _01[cnt];
}

signed main() {
    get(n); rep(i,2,n) get(t1, t2), g[t1].emplace_back(t2), g[t2].emplace_back(t1);
    dfs(1, 0);
    cout << (1ll * f[1][0] + f[1][2] + f[1][3]) % mod;
}

标签:cnt,frac,int,闲话,质数,28,22.10,rep,mod
From: https://www.cnblogs.com/joke3579/p/chitchat221028.html

相关文章

  • PTA-oop第二次博客2022.10.25
    一.前言题目集四:刚刚经历完第三次作业洗礼,紧接着又遇到了如此重量级的凸四边形的计算,一开始是非常痛苦的,由于一开始动手写四边形的计算时还没有学习继承导致四边......
  • 【BZOJ1818】【CQOI2010】【XSY2428】内部白点(树状数组+扫描线)
    先把所有点的\(x\)坐标离散化。然后分别将所有点按\(x\)、\(y\)排序。这里以按\(x\)排序为例,对于\(x\)坐标相同的两个点,我们把它们连成一条线段。那么按\(y\)坐标排序也一......
  • 2022.10.28每日一题
    DaimayuanOnlineJudge-异或和或题目描述对于一个长度为\(n\)的\(01\)序列\(a_1,a_2,…,a_n\)。你可以执行以下操作任意多次:选择两个下标\(1≤i,j≤n(i≠j)\)......
  • git 2022-10-28
    很长时间没有使用git了故重新写一遍关于git操作相关的随笔 1:我用vs做了一个基于qt的空窗口,并成功运行->现在我要把它上传到仓库(gitinit->gitadd.......
  • KubeSphere 社区双周报 | 2022-10-28
    KubeSphere从诞生的第一天起便秉持着开源、开放的理念,并且以社区的方式成长,如今KubeSphere已经成为全球最受欢迎的开源容器平台之一。这些都离不开社区小伙伴的共同努力......
  • 安装JAVA-2022-10-28
    安装JDK百度搜索JDK8,找到下载路径同意协议下载电脑对应版本双击安装记住安装路径配置环境变量我的电脑-右键-属性-环境变量-名字:JAVA_HOME属性......
  • 2022.10.28感悟
    有些东西,维护的不是正义,而是秩序服务性质的工作,最大的忌讳就是投入感情。因为这里需要的是理性,而不是同情。......
  • 强鸡计划(2022/10/28)
    2022/10/28一.fetchSql:作用:输出sql语句。优点:便于调试.二.getField方法是ThinkPHP中用来获取字段值的方法,区别于select和find方法,通常仅用于获取个别字段的值。但是事实......
  • 10月28日Mybatis结果与数据库结果不一致
    Mybatis结果与数据库结果不一致1数据库有结果,而mybatis无结果2数据库1条结果,而mtbatis三条结果报错情况:点击查看代码CreatinganewSqlSessionSqlSession[org.apa......
  • 20221027&20221028 神经网络入门:神经网络判断奇偶数
    神经网络https://www.ibm.com/cn-zh/cloud/learn/neural-networks神经网络反映人类大脑的行为,允许计算机程序识别模式,以及解决人工智能、机器学习和深度学习领域的常见......