0%

21年1月30日 模拟赛

数论 + 斐波那契循环节 + 计数。

A 猫哭了,你哭了吗?

题目

原题 CF1030G

给出长为 n 的均为质数的数列 p1pn,由这个数列可以生成的数列 f 满足:fi(0)=xifi(k)=(aifi(k1)+bi)modpi,其中 ai,bi,xi 是你选定的 [0,pi) 范围的数。求可以生成的不同数列的个数最大值。

n2×105pi2×106

我确实哭了。

对于某一个 i,设 A=ai,B=bi,X=xi,P=pi,那么 fiAfi1+B(modP) 我们显然啊不猜到 fi 的变化轨迹是个 ρ 型环。

设每个 ρ 型环柄长 di,圆环周长 li,合并这些环就是 maxdi+lcmli

套路地,联立 (fi+k)A(fi1+k)(modP),解得 kBA1

已知 f0=X,所以 fiAiX+(Ai1)BA1fnfm(AnAm)X+(AnAm)BA1Am(Anm1)(X+BA1)0

其中 n>m0。这几个部分都考虑一下。

所以可以考虑对 ai 分类讨论:

  • ai=0,显然 di=1li=0

  • ai=1,直接进入环,di=0li=pi

  • ai>1,此时 di=0,可以得到 (An1)(X+BA1)0

    (X+BA1)0l=0,这是不优的,那么 An10,费马小定理得到 n=φ(P)=P1。即 l=pi1

以上几个情况可以定义为选择 1,2,3,我们要对每个 pi 分配选择,使最大化 maxdi+lcmli

由于 di1,先考虑 lcmli。把 pi 倒序排序,设 s 为当前处理过的 lilcm,如果 s 没有包含 pi 这个质因子,我们肯定是尽量选选择 2;否则选选择 3

怎么分配选择 1 的这个 di=1 呢?找一个最没用的。具体地,记录 s 每一个质因数的最高次幂,已经包含这个最高次幂的 li 的个数。再扫一遍所有 li,如果去掉它对 s 无影响,就令它为选择 1

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
typedef long long LL;

const int N = 2e6 + 5;
const int P = 1e9 + 7;

inline int power(int x, int y) {
int res = 1;
while (y) {
if (y & 1) res = (LL)res * x % P;
x = (LL)x * x % P, y >>= 1;
}
return res;
}

int n, cntp, ans;
int a[N], pri[N], ma[N], cnt[N];
bool np[N], wc[N];

inline void get_prime(int lim) {
np[1] = true;
for (int i = 2; i <= lim; ++i) {
if (!np[i]) pri[++cntp] = i;
for (int j = 1; j <= cntp && pri[j] * i <= lim; ++j) {
np[pri[j] * i] = true;
if (i % pri[j] == 0) break;
}
}
}

inline void update(int p, int c) {
if (c > ma[p]) ma[p] = c, cnt[p] = 1;
else if (c == ma[p]) ++cnt[p];
}

inline void deco(int x) {
for (int i = 1; i <= cntp && pri[i] * pri[i] <= x; ++i) {
int p = pri[i];
if (x % p) continue;
int c = 0;
while (x % p == 0) x /= p, ++c;
update(p, c);
}
if (x > 1) update(x, 1);
}

inline bool check(int x) {
if (!np[x]) { // bug
if (ma[x] == 1 && cnt[x] == 1) return false;
return true;
}
for (int i = 1; i <= cntp && pri[i] * pri[i] <= x; ++i) {
int p = pri[i];
if (x % p) continue;
int c = 0;
while (x % p == 0) x /= p, ++c;
if (ma[p] == c && cnt[p] == 1) return false;
}
if (x > 1 && ma[x] == 1 && cnt[x] == 1) return false; // bug
return true;
}

inline void main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
sort(a+1, a+n+1), reverse(a+1, a+n+1);
get_prime(a[1]);
ans = 1;
for (int i = 1; i <= n; ++i) {
if (ma[a[i]]) deco(a[i] - 1), wc[i] = true;
else update(a[i], 1);
}
for (int i = 1; i <= cntp; ++i) {
if (!ma[pri[i]]) continue;
ans = (LL)ans * power(pri[i], ma[pri[i]]) % P;
}
for (int i = 1; i <= n; ++i) {
if ((wc[i] && check(a[i] - 1)) || (!wc[i] && check(a[i]))) {
++ans;
break;
}
}
cout << ans << '\n';
}

B 迫害

题目

已知 g0=ag1=bgi=3gi1gi2f(n,0)=nf(n,k)=f(g(n),k1)

给出 a,b,n,k,p,求 f(n,k)modp

1T10001n1091k1000a,b<p

斐波那契循环节 + 矩阵快速幂。

考场上想写 60 分,随机化找循环节 + O(logn) 快速幂 + 巨大常数,混了个 35 分。

求斐波那契循环节的确定性算法及证明还没懂,先咕。

C 寿司晚宴

题目

n 个寿司排成一排,m 个人,每个人有一个喜欢的寿司,可以以某个寿司的左右侧为起点,朝向喜欢的寿司移动,直到取走并离开;若已经被其他人拿走,方向不变继续走,取走之后遇见的第一份未被取走的寿司后离开,或者直到边界。

求所有人都能取得寿司的方案数。

mn105

先接链成环,在 1n 之间加入 0 号寿司表示断点。

考虑每个人的方向和起点,排列方案数为 2m(n+1)m,除以轮换数 n+1 就是圆排列方案数。

然后我们钦定每个人都能拿到寿司,显然没有人会拿的寿司有 nm+1 个并且不再某个人的路径上,即可以放断点的方案数。

所以最后方案数为: 2m(n+1)m1(nm+1) 代码就没必要了。

Powered By Valine
v1.5.2
  1. 1 だから僕は音楽を辞めた ヨルシカ
  2. 2 ノーチラス ヨルシカ
  3. 3 ただ君に晴れ ヨルシカ
  4. 4 願い~あの頃のキミへ~ 當山みれい
  5. 5 花に亡霊 ヨルシカ
  6. 6 DAYBREAK FRONTLINE 鹿乃
ただ君に晴れ - ヨルシカ
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.