[Codeforces] number theory (R1600) Part.4
题单:https://codeforces.com/problemset/page/1?tags=number+theory%2C1201-1600
566F. Clique in the Divisibility Graph
原题指路:https://codeforces.com/problemset/problem/566/F
题意
无向图中的一个团是一些节点构成的集合,其中任意两点都有边相连.特别的,空集和只包含一个节点的集合也视为团.
对一个元素为正整数的集合 A = { a 1 , ⋯ , a n } A=\{a_1,\cdots,a_n\} A={a1,⋯,an},定义可分性图为:对图中以 a i , a j ∈ A ( i ≠ j ) a_i,a_j\in A\ \ (i\neq j) ai,aj∈A (i=j)为编号的两节点,它们间有边相连当且仅当 a i ∣ a j a_i\mid a_j ai∣aj或 a j ∣ a i a_j\mid a_i aj∣ai.
给定一个包含 n ( 1 ≤ n ≤ 1 e 6 ) n\ \ (1\leq n\leq 1\mathrm{e}6) n (1≤n≤1e6)个正整数的集合 A = { a 1 , ⋯ , a n } ( 1 ≤ a i ≤ 1 e 6 ) A=\{a_1,\cdots,a_n\}\ \ (1\leq a_i\leq 1\mathrm{e}6) A={a1,⋯,an} (1≤ai≤1e6),元素升序给出.对 A A A,求其可分性图中的最大团中的节点数.
思路
将团中的节点升序排列为 x 1 , ⋯ , x k x_1,\cdots,x_k x1,⋯,xk,则 x i ∣ x i + 1 ( 1 ≤ i ≤ k − 1 ) x_i\mid x_{i+1}\ \ (1\leq i\leq k-1) xi∣xi+1 (1≤i≤k−1).
d p [ x ] dp[x] dp[x]表示以 x x x结尾的能构成团的序列长度的最大值.状态转移方程 d p [ x ] = max { 1 , max d ∣ x d p [ d ] + 1 } \displaystyle dp[x]=\max\left\{1,\max_{d\mid x} dp[d]+1\right\} dp[x]=max{1,d∣xmaxdp[d]+1}.
总时间复杂度 n 1 + n 2 + ⋯ + n n = O ( n log n ) \dfrac{n}{1}+\dfrac{n}{2}+\cdots+\dfrac{n}{n}=O(n\log n) 1n+2n+⋯+nn=O(nlogn).
代码
const int MAXN = 1e6 + 5;
int n;
bool cnt[MAXN];
int dp[MAXN]; // dp[x]表示以x结尾的能构成团的序列长度的最大值
void solve() {
CaseT{
int x; cin >> x;
cnt[x] = true;
}
int ans = 0;
for (int i = 1; i <= 1e6; i++) {
if (cnt[i]) {
ans = max(ans, ++dp[i]);
for (int j = i; j <= 1e6; j += i) dp[j] = max(dp[j], dp[i]);
}
}
cout << ans;
}
int main() {
solve();
}
568A. Primes or Palindromes?
原题指路:https://codeforces.com/problemset/problem/568/A
题意 ( 3 s 3\ \mathrm{s} 3 s)
对正整数 n n n,定义 π ( n ) \pi(n) π(n)为不大于 n n n的素数的个数, r u b ( n ) rub(n) rub(n)为不大于 n n n的回文数的个数.给定 A = p q ( 1 ≤ p , q ≤ 1 e 4 , 1 42 ≤ p q ≤ 42 ) A=\dfrac{p}{q}\ \ \left(1\leq p,q\leq 1\mathrm{e}4,\dfrac{1}{42}\leq \dfrac{p}{q}\leq 42\right) A=qp (1≤p,q≤1e4,421≤qp≤42),求最大的正整数 n s . t . π ( n ) ≤ A ⋅ r u b ( n ) n\ s.t.\ \pi(n)\leq A\cdot rub(n) n s.t. π(n)≤A⋅rub(n),无解输出"Palindromic tree is better than splay tree".
思路
π ( n ) ∼ n ln n \pi(n)\sim \dfrac{n}{\ln n} π(n)∼lnnn.长度为 k k k的回文数的个数约 1 0 ⌊ k + 1 2 ⌋ 10^{\left\lfloor\frac{k+1}{2}\right\rfloor} 10⌊2k+1⌋,是 O ( n ) O(\sqrt{n}) O(n)的级别.故 A ∼ n ln n A\sim \dfrac{\sqrt{n}}{\ln n} A∼lnnn,则 n < 1 e 7 n<1\mathrm{e}7 n<1e7.
筛出 1 e 7 1\mathrm{e}7 1e7内的素数后求 π ( n ) \pi(n) π(n)的前缀和,再求出 1 e 7 1\mathrm{e}7 1e7内的数的 r u b ( n ) rub(n) rub(n)的前缀和即可,总时间复杂度 O ( a n s ⋅ log log a n s ) O(ans\cdot \log\log ans) O(ans⋅loglogans).
事实上,对 A ≤ 42 , a n s ≤ 2 e 6 A\leq 42,ans\leq 2\mathrm{e}6 A≤42,ans≤2e6.
代码
const int MAXN = 2e6 + 5;
bool prime[MAXN] = { true };
int prepi[MAXN], prerub[MAXN]; // pi(n)和rub(n)的前缀和
bool check(int n) { // 判断n是否为回文数
string s = to_string(n), tmps = s;
reverse(all(s));
return s == tmps;
}
void init() {
for (int i = 2; i < MAXN; i++) prime[i] = true;
for (int i = 2; i < MAXN; i++) {
if (!prime[i]) continue;
for (int j = 2 * i; j < MAXN; j += i) prime[j] = false;
}
for (int i = 2; i < MAXN; i++) prepi[i] = prepi[i - 1] + prime[i];
for (int i = 1; i < MAXN; i++) prerub[i] = prerub[i - 1] + check(i);
}
void solve() {
init();
int p, q; cin >> p >> q;
for (int i = MAXN - 1;; i--) {
if (q * prepi[i] <= p * prerub[i]) {
cout << i;
return;
}
}
}
int main() {
solve();
}
573A. Bear and Poker
原题指路:https://codeforces.com/problemset/problem/573/A
题意 ( 2 s 2\ \mathrm{s} 2 s)
给定一个长度为 n ( 2 ≤ n ≤ 1 e 5 ) n\ \ (2\leq n\leq 1\mathrm{e}5) n (2≤n≤1e5)的序列 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}9) a1,⋯,an (1≤ai≤1e9).现有操作:选择一个下标 i ( 1 ≤ i ≤ n ) i\ \ (1\leq i\leq n) i (1≤i≤n),令 a i ∗ = 2 a_i*=2 ai∗=2或 a i ∗ = 3 a_i*=3 ai∗=3.问经过若干次操作后能否使得序列元素相等,若能则输出"Yes";否则输出"No".
思路
判断所有 a i a_i ai除 2 , 3 2,3 2,3外的素因子之积是否相等即可.
代码
void solve() {
int n; cin >> n;
vi a(n);
for (auto& ai : a) {
cin >> ai;
while (ai % 2 == 0) ai /= 2;
while (ai % 3 == 0) ai /= 3;
}
cout << (a == vi(n, a[0]) ? "Yes" : "No");
}
int main() {
solve();
}
576A. Vasya and Petya’s Game
原题指路:https://codeforces.com/problemset/problem/576/A
题意
A和B玩游戏.A想一个整数 x ∈ [ 1 , n ] ( 1 ≤ n ≤ 1000 ) x\in [1,n]\ \ (1\leq n\leq 1000) x∈[1,n] (1≤n≤1000),B猜该数.B每次可询问 x x x是否整除某整数 y ( 1 ≤ y ≤ n ) y\ \ (1\leq y\leq n) y (1≤y≤n),A会回答其问题.问B至少问多少个问题能确定 x x x,先输出问题数,再输出每个问题的 y y y.若有多组问题数最少的解,输出任一组.
思路
对 n n n的某个素因子 p p p,若B不问 p k ( k ≥ 1 ) p^k\ \ (k\geq 1) pk (k≥1),则他无法分辨 p k − 1 p^{k-1} pk−1和 p k p^k pk,故B需问 ≤ n \leq n ≤n的所有素数及其不超过 n n n的幂次.
代码
const int MAXN = 1005;
int primes[MAXN], cnt;
bool state[MAXN];
void init() {
state[0] = state[1] = true;
for (int i = 2; i * i < MAXN; i++) {
if (!state[i])
for (int j = i * i; j < MAXN; j += i) state[j] = true;
}
}
void solve() {
init();
int n; cin >> n;
vi ans;
for (int i = 1; i <= n; i++) {
if (!state[i]) {
int cur = 1;
while (cur <= n / i) {
cur *= i;
ans.push_back(cur);
}
}
}
cout << ans.size() << endl;
for (auto i : ans) cout << i << ' ';
}
int main() {
solve();
}
626C. Block Towers
原题指路:https://codeforces.com/problemset/problem/626/C
题意 ( 2 s ) (2\ \mathrm{s}) (2 s)
有A和B两种砖,分别由 2 2 2、 3 3 3个方块组成.现分别用两种砖横放堆叠造塔,使得任意两塔包含的方块数不同,共造出了 n n n座用A型砖构成的塔和 m m m座用B型砖构成的塔.给定两整数 n , m ( 0 ≤ n , m ≤ 1 e 6 , n + m > 0 ) n,m\ \ (0\leq n,m\leq 1\mathrm{e}6,n+m>0) n,m (0≤n,m≤1e6,n+m>0)问最高的塔的高度的最小值.
思路
设答案为 a n s ans ans,则至少有 n n n个不超过 a n s ans ans的 2 2 2的倍数、 m m m个不超过 a n s ans ans的 3 3 3的倍数、 ( n + m ) (n+m) (n+m)个 2 2 2或 3 3 3的倍数,即 n ≤ ⌊ a n s 2 ⌋ , m ≤ ⌊ a n s 3 ⌋ , n + m ≤ ⌊ a n s 2 ⌋ + ⌊ a n s 3 ⌋ − ⌊ a n s 6 ⌋ n\leq\left\lfloor\dfrac{ans}{2}\right\rfloor,m\leq \left\lfloor\dfrac{ans}{3}\right\rfloor,n+m\leq \left\lfloor\dfrac{ans}{2}\right\rfloor+\left\lfloor\dfrac{ans}{3}\right\rfloor-\left\lfloor\dfrac{ans}{6}\right\rfloor n≤⌊2ans⌋,m≤⌊3ans⌋,n+m≤⌊2ans⌋+⌊3ans⌋−⌊6ans⌋,二分即可.
移项知 a n s ≥ 3 2 ( n + m ) ans\geq\dfrac{3}{2}(n+m) ans≥23(n+m),故二分上界可取 3 e 6 3\mathrm{e}6 3e6.
代码
void solve() {
int n, m; cin >> n >> m;
int l = 1, r = 3e6;
while (l < r) {
int mid = l + r >> 1;
if (n <= mid / 2 && m <= mid / 3 && n + m <= mid / 2 + mid / 3 - mid / 6) r = mid;
else l = mid + 1;
}
cout << l;
}
int main() {
solve();
}
630K. Indivisibility
原题指路:https://codeforces.com/problemset/problem/630/K
题意 ( 0.5 s 0.5\ \mathrm{s} 0.5 s)
给定整数 n ( 1 ≤ n ≤ 1 e 18 ) n\ \ (1\leq n\leq 1\mathrm{e}18) n (1≤n≤1e18),求 [ 1 , n ] [1,n] [1,n]中有多少个数不能被 2 ∼ 10 2\sim 10 2∼10整除.
思路
容斥, a n s = n − ⌊ n 2 ⌋ − ⌊ n 3 ⌋ − ⌊ n 5 ⌋ − ⌊ n 7 ⌋ ans=n-\left\lfloor\dfrac{n}{2}\right\rfloor-\left\lfloor\dfrac{n}{3}\right\rfloor-\left\lfloor\dfrac{n}{5}\right\rfloor-\left\lfloor\dfrac{n}{7}\right\rfloor ans=n−⌊2n⌋−⌊3n⌋−⌊5n⌋−⌊7n⌋
+ ⌊ n 2 ⋅ 3 ⌋ + ⌊ n 2 ⋅ 5 ⌋ + ⌊ n 2 ⋅ 7 ⌋ + ⌊ n 3 ⋅ 5 ⌋ + ⌊ n 3 ⋅ 7 ⌋ + ⌊ n 5 ⋅ 7 ⌋ +\left\lfloor\dfrac{n}{2\cdot 3}\right\rfloor+\left\lfloor\dfrac{n}{2\cdot 5}\right\rfloor+\left\lfloor\dfrac{n}{2\cdot 7}\right\rfloor+\left\lfloor\dfrac{n}{3\cdot 5}\right\rfloor+\left\lfloor\dfrac{n}{3\cdot 7}\right\rfloor+\left\lfloor\dfrac{n}{5\cdot 7}\right\rfloor +⌊2⋅3n⌋+⌊2⋅5n⌋+⌊2⋅7n⌋+⌊3⋅5n⌋+⌊3⋅7n⌋+⌊5⋅7n⌋
− ⌊ n 2 ⋅ 3 ⋅ 5 ⌋ − ⌊ n 2 ⋅ 3 ⋅ 7 ⌋ − ⌊ n 2 ⋅ 5 ⋅ 7 ⌋ − ⌊ n 3 ⋅ 5 ⋅ 7 ⌋ + ⌊ n 2 ⋅ 3 ⋅ 5 ⋅ 7 ⌋ -\left\lfloor\dfrac{n}{2\cdot 3\cdot 5}\right\rfloor-\left\lfloor\dfrac{n}{2\cdot 3\cdot 7}\right\rfloor-\left\lfloor\dfrac{n}{2\cdot 5\cdot 7}\right\rfloor-\left\lfloor\dfrac{n}{3\cdot 5\cdot 7}\right\rfloor+\left\lfloor\dfrac{n}{2\cdot 3\cdot 5\cdot 7}\right\rfloor −⌊2⋅3⋅5n⌋−⌊2⋅3⋅7n⌋−⌊2⋅5⋅7n⌋−⌊3⋅5⋅7n⌋+⌊2⋅3⋅5⋅7n⌋.
代码
void solve() {
ll n; cin >> n;
cout << n - n / 2 - n / 3 - n / 5 - n / 7
+ n / (2 * 3) + n / (2 * 5) + n / (2 * 7) + n / (3 * 5) + n / (3 * 7) + n / (5 * 7)
- n / (2 * 3 * 5) - n / (2 * 3 * 7) - n / (2 * 5 * 7) - n / (3 * 5 * 7)
+ n / (2 * 3 * 5 * 7);
}
int main() {
solve();
}
633B. A Trivial Problem
原题指路:https://codeforces.com/problemset/problem/633/B
题意 ( 2 s 2\ \mathrm{s} 2 s)
给定一个整数 m ( 1 ≤ m ≤ 1 e 5 ) m\ \ (1\leq m\leq 1\mathrm{e}5) m (1≤m≤1e5),求所有使得 n ! n! n!以 m m m个零结尾的正整数 n n n,第一行输出个数,第二行输出所有 n n n.
思路
n ! n! n!后缀零的个数等于 n n n的素因子 5 5 5的个数.
注意到每相邻十个数至多会为 n ! n! n!贡献一个后缀零,故只需枚举 [ 1 , 10 m ] [1,10m] [1,10m]即可.
代码
void solve() {
int n; cin >> n;
vi ans;
int cnt = 0; // 素因子5的个数
for (int i = 1; i < 10 * n; i++) {
int cur = i;
while (cur % 5 == 0) {
cur /= 5;
cnt++;
}
if (cnt == n) ans.push_back(i);
else if (cnt > n) break;
}
cout << ans.size() << endl;
for (auto i : ans) cout << i << ' ';
}
int main() {
solve();
}
678C. Joty and Chocolate
原题指路:https://codeforces.com/problemset/problem/678/C
题意
有编号 1 ∼ n 1\sim n 1∼n的 n n n个物品.现以某种顺序对它们染色,若该物品的编号能被 a a a整除,则染红色;若该物品的编号能被 b b b整除,则染蓝色;若该物品的编号同时被 a a a和 b b b整除,则只能染一种颜色.染色结束后,每个染红色的物品可获得 p p p的收益,每个染蓝色的物品可获得 q q q的收益.求最大收益.
第一行输入五个整数 n , a , b , p , q ( 1 ≤ n , a , b , p , q ≤ 1 e 9 ) n,a,b,p,q\ \ (1\leq n,a,b,p,q\leq 1\mathrm{e}9) n,a,b,p,q (1≤n,a,b,p,q≤1e9).
思路
一个物品可选择染红色或蓝色当且仅当其编号是 l c m ( a , b ) \mathrm{lcm}(a,b) lcm(a,b)的倍数,这样的物品应染收益更大的颜色.
显然 a n s = p ⋅ ⌊ n a ⌋ + q ⋅ ⌊ n b ⌋ − min ( p , q ) ⋅ ⌊ n l c m ( a , b ) ⌋ ans=p\cdot\left\lfloor\dfrac{n}{a}\right\rfloor+q\cdot \left\lfloor\dfrac{n}{b}\right\rfloor-\min(p,q)\cdot \left\lfloor\dfrac{n}{\mathrm{lcm}(a,b)}\right\rfloor ans=p⋅⌊an⌋+q⋅⌊bn⌋−min(p,q)⋅⌊lcm(a,b)n⌋.
代码
void solve() {
ll n, a, b, p, q; cin >> n >> a >> b >> p >> q;
cout << n / a * p + n / b * q - n / lcm(a, b) * min(p, q);
}
int main() {
solve();
}
707C. Pythagorean Triples
原题指路:https://codeforces.com/problemset/problem/707/C
题意
给定一个整数 n ( 1 ≤ n ≤ 1 e 9 ) n\ \ (1\leq n\leq 1\mathrm{e}9) n (1≤n≤1e9),问是否存在一个边长都为整数的直角三角形,使得 n n n为其中一条边的边长.若有解则输出任一组解;否则输出 − 1 -1 −1.
思路
设 n n n是直角三角形的短直角边的边长, n 2 + m 2 = k 2 n^2+m^2=k^2 n2+m2=k2,则 n 2 = ( k + m ) ( k − m ) n^2=(k+m)(k-m) n2=(k+m)(k−m).
① n n n为奇数时,取 k + m = n 2 , k − m = 1 k+m=n^2,k-m=1 k+m=n2,k−m=1,则 m = n 2 − 1 2 , k = n 2 + 1 2 m=\dfrac{n^2-1}{2},k=\dfrac{n^2+1}{2} m=2n2−1,k=2n2+1.
② n n n为偶数时,取 k + m = n 2 2 , k − m = 2 k+m=\dfrac{n^2}{2},k-m=2 k+m=2n2,k−m=2,则 m = n 2 4 − 1 , k = n 2 4 + 1 m=\dfrac{n^2}{4}-1,k=\dfrac{n^2}{4}+1 m=4n2−1,k=4n2+1.
显然 n = 1 , 2 n=1,2 n=1,2时无解.
代码
void solve() {
ll n; cin >> n;
if (n <= 2) cout << -1;
else if (n & 1) cout << (n * n - 1) / 2 << ' ' << (n * n + 1) / 2;
else cout << n * n / 4 - 1 << ' ' << n * n / 4 + 1;
}
int main() {
solve();
}
735D. Taxes
原题指路:https://codeforces.com/problemset/problem/735/D
题意 ( 2 s 2\ \mathrm{s} 2 s)
若收益为 n ( 2 ≤ n ≤ 2 e 9 ) n\ \ (2\leq n\leq 2\mathrm{e}9) n (2≤n≤2e9)元,则需交税最大的非 n n n的约数元.现将 n n n拆成 k k k份,即 n 1 + ⋯ + n k = n ( k ≥ 1 ) n_1+\cdots+n_k=n\ \ (k\geq 1) n1+⋯+nk=n (k≥1),每份分别交税,问最少要交多少税.
思路
(1) n n n为素数时, a n s = 1 ans=1 ans=1.
(2) n n n非素数时, a n s ≥ 2 ans\geq 2 ans≥2.
①若 n n n是 ≥ 4 \geq 4 ≥4的偶数,由Goldbach猜想: n n n可表示为两素数之和,此时 a n s = 2 ans=2 ans=2.
②若 n n n是奇数,因 n = 2 + ( n − 2 ) n=2+(n-2) n=2+(n−2),
i)若 ( n − 2 ) (n-2) (n−2)是素数,则 a n s = 2 ans=2 ans=2.
ii)若 ( n − 2 ) (n-2) (n−2)是合数,由弱Goldbach猜想: n n n可表示为三个奇素数之和,此时 a n s = 3 ans=3 ans=3.
代码
bool check(int n) { // 判断是否是素数
if (n <= 2) return n == 2;
for (int i = 2; i <= sqrt(n); i++)
if (n % i == 0) return false;
return true;
}
void solve() {
int n; cin >> n;
if (check(n)) cout << 1;
else if (n % 2 == 0) cout << 2;
else cout << (check(n - 2) ? 2 : 3);
}
int main() {
solve();
}