题意:有一个长度为n的数组a和一个长度为m的数组b,一个素数p。有n个集合,初始都只有一个1。现在,对(i从1到n)第i个集合执行以下操作:

对所有集合中的元素c,把c * (a[i] ^ b[j]) mod p 加入集合(j从1到m), 直到集合的元素不再增加为止。

问最后这n个集合的并有多少个元素?

n到1e4, m到1e5, p到1e9。

思路(官方题解)这题运用了很多数论的知识,不对数论有一定了解比较难做出这道题。

涉及的知识:原根,阶,欧拉定理,贝祖定理。

首先我们知道,x ^ y mod p = x ^ (y mod phi(p)) mod p(欧拉定理),而集合的操作可以看成a的指数相加,所以我们第一步先求出所有b和p - 1的gcd = t,这样每个集合的大小是(p - 1) / t,(贝祖定理),集合中的元素为a[i] ^ (k * t)。但是,由于a是不一定相同的,所以我们很难直接合并。我们可以转化成原根的形式,那么假设g ^ (r[i]) = a[i], ,令q[i] = gcd(r[i], p - 1)(贝祖定理)。我们不妨令g = g ^ t,因为t是一个常数。那么,现在集合中的元素为g ^ (q[i] * k), 我们现在需要求出q[i]。怎么求q[i]呢?我们只要求出a[i] ^ t的阶 = l,然后(p - 1) / l就是q[i], 为什么呢?因为(a[i] ^ t) ^ l mod p = 1 mod p = g ^ (p - 1) mod p => a[i] ^ t mod p= g ^ ((p - 1) / l) mod p, 这样就可以算出对应的q[i],即a[i] ^ t的原根中的指标。现在我们求出了q[i],那么所有g ^ (q[i] * k)会出现在集合中。一种想法是用筛法,但是p很大,不能筛。这里需要用到容斥原理。

注意,cf上很多代码的容斥是假的,可以被hack。

以下是来自cf评论区的两个数据:

2 1 13

3 5

1

答案:6

2 1 37

31 27

1

答案:8

正确容斥做法:先处理出p - 1的所有因子,从大到小枚举,枚举因子时判断是否有q[i],始得这个因子是q[i]的倍数,如果有,说明这个因子可以对答案产生贡献,再枚举比它大的因子,如果有因子是这个因子的倍数,那么减去这个因子的贡献。最后剩下的是这个因子的贡献。如果没有,跳过即可。均摊的复杂度应该是O(log ^ 2(p))。

代码:

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 100010;
int n, m, p;
int a[maxn], b[maxn], q[maxn], dp[maxn];
int qpow(int x, int y) {
int ans = 1;
for (; y; y >>= 1) {
if(y & 1) ans = ((LL)ans * x) % p;
x = ((LL)x * x) % p;
}
return ans;
}
vector<int> re;
void div(int x) {
for (int i = 1; i * i <= x; i++) {
if(x % i == 0) {
re.push_back(i);
if(i * i != x)
re.push_back(x / i);
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &p);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
int t = p - 1;
for (int i = 1; i <= m; i++) {
scanf("%d", &b[i]);
t = __gcd(t, b[i]);
}
div(p - 1);
sort(re.begin(), re.end());
for (int i = 1; i <= n; i++) {
a[i] = qpow(a[i], t);
for (int j = 0; j < re.size(); j++) {
if(qpow(a[i], re[j]) == 1) {
q[i] = (p - 1) / re[j];
break;
}
}
}
sort(q + 1, q + 1 + n);
n = unique(q + 1, q + 1 + n) - (q + 1);
int ans = 0;
for (int j = re.size() - 1; j >= 0; j--) {
bool flag = 0;
for (int i = 1; i <= n; i++) {
if(re[j] % q[i] == 0) {
flag = 1;
for (int k = j + 1; k < re.size(); k++) {
if(re[k] % re[j] == 0)
dp[j] -= dp[k];
}
break;
}
}
if(flag) {
dp[j] += (p - 1) / re[j];
ans += dp[j];
}
}
printf("%d\n", ans);
}

Codeforces 360D Levko and Sets (数论好题)的更多相关文章

  1. [CodeForces - 1225D]Power Products 【数论】 【分解质因数】

    [CodeForces - 1225D]Power Products [数论] [分解质因数] 标签:题解 codeforces题解 数论 题目描述 Time limit 2000 ms Memory ...

  2. Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论

    Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论 题意 给你一段数,然后小明去猜某一区间内的gcd,这里不一定是准确值,如果在这个区间内改变 ...

  3. Codeforces Round #609 (Div. 2)前五题题解

    Codeforces Round #609 (Div. 2)前五题题解 补题补题…… C题写挂了好几个次,最后一题看了好久题解才懂……我太迟钝了…… 然后因为longlong调了半个小时…… A.Eq ...

  4. Codeforces 515C 题解(贪心+数论)(思维题)

    题面 传送门:http://codeforces.com/problemset/problem/515/C Drazil is playing a math game with Varda. Let’ ...

  5. Codeforces 571E - Geometric Progressions(数论+阿巴细节题)

    Codeforces 题目传送门 & 洛谷题目传送门 u1s1 感觉此题思维难度不太大,不过大概是细节多得到了精神污染的地步所以才放到 D1E 的罢((( 首先我们对所有 \(a_i,b_i\ ...

  6. Coprime Arrays CodeForces - 915G (数论水题)

    反演一下可以得到$b_i=\sum\limits_{d=1}^i{\mu(i)(\lfloor \frac{i}{d} \rfloor})^n$ 整除分块的话会T, 可以维护一个差分, 优化到$O(n ...

  7. [BZOJ1951][SDOI2005]古代猪文(数论好题)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1951 分析: 练习数论知识的好题,涉及到费马小定理.lucas定理.求逆元

  8. Educational Codeforces Round 7 B. The Time 水题

    B. The Time 题目连接: http://www.codeforces.com/contest/622/problem/B Description You are given the curr ...

  9. Educational Codeforces Round 7 A. Infinite Sequence 水题

    A. Infinite Sequence 题目连接: http://www.codeforces.com/contest/622/problem/A Description Consider the ...

随机推荐

  1. sql查询时间范围

    select * from table where Time>='2019-05-09 00:05:36' and Time<='2019-05-10 00:05:36'

  2. CentOS7.2安装Oracle12.1.0.2

    Centos7.2环境安装(安装桌面) #安装界面 #查看版本 cat /etc/redhat-release #查看连接 ifconfig eth0 echo "127.0.0.1 tes ...

  3. The main Method

    The main Method You can call static methods without having any objects. For example, you never const ...

  4. .Net Core 使用 Swagger 提供API文档

    1.运行环境 开发工具:Visual Studio 2017 JDK版本:.NET Core 2.0 项目管理工具:nuget 2.GITHUB地址 https://github.com/nbfujx ...

  5. DM9000网卡驱动深度分析

    一.dm9000_porbe函数分析 不同于u-boot代码,tq2440中的DM9000更加复杂,需要分析的点也很多: /* * Search DM9000 board, allocate spac ...

  6. k-近邻算法(kNN)完整代码

    from numpy import *#科学计算包 from numpy import tile from numpy import zeros import operator #运算符模块 impo ...

  7. 【BZOJ2555】SubString(后缀自动机,LCT)

    题意:给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 长度 <= ...

  8. BZOJ 4484: [Jsoi2015]最小表示(拓扑排序+bitset)

    传送门 解题思路 \(bitset\)维护连通性,给每个点开个\(bitset\),第\(i\)位为\(1\)则表示与第\(i\)位联通.算答案时显然要枚举每条边,而枚举边的顺序需要贪心,一个点先到达 ...

  9. HihoCoder - 1673 (单调队列)

    题目:https://vjudge.net/contest/319166#problem/A 题意:有一个01矩阵,求一个最大子矩阵面积,这个矩阵要求里面都是01间隔,没有0或1连续 思路:这个题其实 ...

  10. Bugku | 数字验证正则绕过

    语法: int preg_match_all (字符串$ pattern ,字符串$ subject [,数组和$ matches [,整数$ flags = PREG_PATTERN_ORDER [ ...