[Codeforces] number theory (R1600) Part.4

[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,ajA  (i=j)为编号的两节点,它们间有边相连当且仅当 a i ∣ a j a_i\mid a_j aiaj a j ∣ a i a_j\mid a_i ajai.

给定一个包含 n    ( 1 ≤ n ≤ 1 e 6 ) n\ \ (1\leq n\leq 1\mathrm{e}6) n  (1n1e6)个正整数的集合 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}  (1ai1e6),元素升序给出.对 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) xixi+1  (1ik1).

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,dxmaxdp[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  (1p,q1e4,421qp42),求最大的正整数 n   s . t .   π ( n ) ≤ A ⋅ r u b ( n ) n\ s.t.\ \pi(n)\leq A\cdot rub(n) n s.t. π(n)Arub(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} 102k+1,是 O ( n ) O(\sqrt{n}) O(n )的级别.故 A ∼ n ln ⁡ n A\sim \dfrac{\sqrt{n}}{\ln n} Alnnn ,则 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(ansloglogans).

事实上,对 A ≤ 42 , a n s ≤ 2 e 6 A\leq 42,ans\leq 2\mathrm{e}6 A42,ans2e6.

代码

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  (2n1e5)的序列 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  (1ai1e9).现有操作:选择一个下标 i    ( 1 ≤ i ≤ n ) i\ \ (1\leq i\leq n) i  (1in),令 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]  (1n1000),B猜该数.B每次可询问 x x x是否整除某整数 y    ( 1 ≤ y ≤ n ) y\ \ (1\leq y\leq n) y  (1yn),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  (k1),则他无法分辨 p k − 1 p^{k-1} pk1 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  (0n,m1e6,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 n2ans,m3ans,n+m2ans+3ans6ans,二分即可.

移项知 a n s ≥ 3 2 ( n + m ) ans\geq\dfrac{3}{2}(n+m) ans23(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  (1n1e18),求 [ 1 , n ] [1,n] [1,n]中有多少个数不能被 2 ∼ 10 2\sim 10 210整除.

思路

容斥, 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=n2n3n5n7n

+ ⌊ 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 +23n+25n+27n+35n+37n+57n

− ⌊ 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 235n237n257n357n+2357n.

代码

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  (1m1e5),求所有使得 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 1n 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  (1n,a,b,p,q1e9).

思路

一个物品可选择染红色或蓝色当且仅当其编号是 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=pan+qbnmin(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  (1n1e9),问是否存在一个边长都为整数的直角三角形,使得 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)(km).

n n n为奇数时,取 k + m = n 2 , k − m = 1 k+m=n^2,k-m=1 k+m=n2,km=1,则 m = n 2 − 1 2 , k = n 2 + 1 2 m=\dfrac{n^2-1}{2},k=\dfrac{n^2+1}{2} m=2n21,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,km=2,则 m = n 2 4 − 1 , k = n 2 4 + 1 m=\dfrac{n^2}{4}-1,k=\dfrac{n^2}{4}+1 m=4n21,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  (2n2e9)元,则需交税最大的非 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  (k1),每份分别交税,问最少要交多少税.

思路

(1) n n n为素数时, a n s = 1 ans=1 ans=1.

(2) n n n非素数时, a n s ≥ 2 ans\geq 2 ans2.

​ ①若 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+(n2),

​ i)若 ( n − 2 ) (n-2) (n2)是素数,则 a n s = 2 ans=2 ans=2.

​ ii)若 ( n − 2 ) (n-2) (n2)是合数,由弱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();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值