[Codeforces] number theory (R1600) Part.5

[Codeforces] number theory (R1600) Part.5

题单:https://codeforces.com/problemset/page/1?tags=number+theory%2C1201-1600

742B. Arpa’s obvious problem and Mehrdad’s terrible solution

原题指路:https://codeforces.com/problemset/problem/742/B

题意

给定一个长度为 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5)的序列 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ 1 e 5 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}5) a1,,an  (1ai1e5)和一个整数 x    ( 0 ≤ x ≤ 1 e 5 ) x\ \ (0\leq x\leq 1\mathrm{e}5) x  (0x1e5).求使得 1 ≤ i < j ≤ n 1\leq i<j\leq n 1i<jn a i   x o r   a j = x a_i\ \mathrm{xor}\ a_j=x ai xor aj=x的数对 ( i , j ) (i,j) (i,j)的个数.

思路

c n t [ x ] cnt[x] cnt[x]表示数 x x x的出现个数,扫一遍即可.

注意 x   x o r   y x\ \mathrm{xor}\ y x xor y最大可取到 2 max ⁡ { x , y } 2\max\{x,y\} 2max{x,y}.注意答案可能爆int.

代码

const int MAXN = 2e5 + 5;  // 两倍空间
int cnt[MAXN];

void solve() {
  int n, x; cin >> n >> x;
  ll ans = 0;
  while (n--) {
    int a; cin >> a;
    ans += cnt[a ^ x];
    cnt[a]++;
  }
  cout << ans;
}

int main() {
  solve();
}


743C. Vladik and fractions

原题指路:https://codeforces.com/problemset/problem/743/C

题意

给定一个整数 n    ( 1 ≤ n ≤ 1 e 4 ) n\ \ (1\leq n\leq 1\mathrm{e}4) n  (1n1e4),求三个相异的整数 x , y , z    ( 1 ≤ x , y , z ≤ 1 e 9 )   s . t .   2 n = 1 x + 1 y + 1 z x,y,z\ \ (1\leq x,y,z\leq 1\mathrm{e}9)\ s.t.\ \dfrac{2}{n}=\dfrac{1}{x}+\dfrac{1}{y}+\dfrac{1}{z} x,y,z  (1x,y,z1e9) s.t. n2=x1+y1+z1,无解则输出 − 1 -1 1.

思路

注意到 2 n = 1 n + 1 n + 1 + 1 n ( n + 1 ) \dfrac{2}{n}=\dfrac{1}{n}+\dfrac{1}{n+1}+\dfrac{1}{n(n+1)} n2=n1+n+11+n(n+1)1,取 x = n , y = n + 1 , z = n ( n + 1 ) x=n,y=n+1,z=n(n+1) x=n,y=n+1,z=n(n+1),显然 x , y , z ≤ 1 e 9 x,y,z\leq 1\mathrm{e}9 x,y,z1e9.

注意 n = 1 n=1 n=1时无解.

代码

void solve() {
  int n; cin >> n;

  if (n == 1) cout << -1;
  else cout << n << ' ' << n + 1 << ' ' << n * (n + 1);
}

int main() {
  solve();
}


757B. Bash’s Big Day

原题指路:https://codeforces.com/problemset/problem/757/B

题意 ( 2   s 2\ \mathrm{s} 2 s)

给定 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5)个数 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ 1 e 5 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}5) a1,,an  (1ai1e5),从中取最多的数 a 1 , ⋯   , a k   s . t .   gcd ⁡ ( a 1 , ⋯   , a k ) > 1 a_1,\cdots,a_k\ s.t.\ \gcd(a_1,\cdots,a_k)>1 a1,,ak s.t. gcd(a1,,ak)>1,特别地,可单独取一个 a i = 1 a_i=1 ai=1的数.问最多能取多少个数.

思路

对每个 a i a_i ai素因数分解,预处理出每个素因子的出现次数,取最多的即可.

代码

const int MAXN = 1e5 + 5;
umap<int, int> cnt;  // 素因子出现次数

void solve() {
  CaseT{
    int a; cin >> a;
    for (int i = 2; i <= sqrt(a); i++) {
      if (a % i == 0) {
        cnt[i]++;
        while (a % i == 0) a /= i;
      }
    }
    if (a > 1) cnt[a]++;
  }

  int ans = 1;
  for (auto [u, v] : cnt) ans = max(ans, v);
  cout << ans;
}

int main() {
  solve();
}


762A. k-th divisor

原题指路:https://codeforces.com/problemset/problem/762/A

题意 ( 2   s 2\ \mathrm{s} 2 s)

给定两整数 n , k    ( 1 ≤ n ≤ 1 e 15 , 1 ≤ k ≤ 1 e 9 ) n,k\ \ (1\leq n\leq 1\mathrm{e}15,1\leq k\leq 1\mathrm{e}9) n,k  (1n1e15,1k1e9),求 n n n的第 k k k小的约数,无解输出 − 1 -1 1.

思路

O ( n ) O\left(\sqrt{n}\right) O(n )预处理出 n n n的约数即可.

代码

void solve() {
  ll n; int k; cin >> n >> k;

  vl divisors;  // 注意ll
  for (int i = 1; i <= sqrt(n); i++) {
    if (n % i == 0) {
      divisors.push_back(i);
      if (i != n / i) divisors.push_back(n / i);
    }
  }

  if (divisors.size() < k) cout << -1;
  else {
    sort(all(divisors));
    cout << divisors[k - 1];
  }
}

int main() {
  solve();
}


840A. Leha and Function

原题指路:https://codeforces.com/problemset/problem/840/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

考察从 n n n个元素 [ 1 , ⋯   , n ] [1,\cdots,n] [1,,n]中选 k k k个元素构成一个子集,定义 f ( n , k ) f(n,k) f(n,k)表示所有子集中最小元素的期望.

给定两长度为 n    ( 1 ≤ n ≤ 2 e 5 ) n\ \ (1\leq n\leq 2\mathrm{e}5) n  (1n2e5)的序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an b 1 , ⋯   , b n    ( 1 ≤ a i , b i ≤ 1 e 9 ) b_1,\cdots,b_n\ \ (1\leq a_i,b_i\leq 1\mathrm{e}9) b1,,bn  (1ai,bi1e9).将序列 a [ ] a[] a[]重排为序列 a ′ [ ]   s . t .   ∑ i = 1 n f ( a i , b i ) a'[]\ s.t.\ \displaystyle\sum_{i=1}^n f(a_i,b_i) a[] s.t. i=1nf(ai,bi)最大,输出任一满足条件的序列 a ′ [ ] a'[] a[].

思路

n n n个元素中选 k k k个元素的方案数为 C n k C_n^k Cnk.枚举 i i i,为使得其是子集中最小的元素,应在比它大的 ( n − i ) (n-i) (ni)个元素中选 ( k − 1 ) (k-1) (k1)个元素,故 f ( n , k ) = ∑ i = 1 n − k + 1 i ⋅ C n − i k − 1 C n k f(n,k)=\dfrac{\displaystyle\sum_{i=1}^{n-k+1} i\cdot C_{n-i}^{k-1}}{C_n^k} f(n,k)=Cnki=1nk+1iCnik1.

注意到 f ( n , k ) f ( n , k − 1 ) = k k + 1 \dfrac{f(n,k)}{f(n,k-1)}=\dfrac{k}{k+1} f(n,k1)f(n,k)=k+1k,则 f ( n , k ) = n + 1 k + 1 f(n,k)=\dfrac{n+1}{k+1} f(n,k)=k+1n+1.为使得 f ( n , k ) f(n,k) f(n,k)尽量大,应让较大的 n n n与较小的 k k k配对.

将序列 a [ ] a[] a[]降序排列、 b [ ] b[] b[]升序排列后配对即可.

代码

void solve() {
  int n; cin >> n;
  vi a(n);
  vii b(n);
  for (auto& ai : a) cin >> ai;
  for (int i = 0; i < n; i++) {
    cin >> b[i].first;
    b[i].second = i;
  }

  sort(all(a), greater<int>()), sort(all(b));

  vi ans(n);
  for (int i = 0; i < n; i++) ans[b[i].second] = a[i];
  for (int i = 0; i < n; i++) cout << ans[i] << " \n"[i == n - 1];
}

int main() {
  solve();
}


870C. Maximum splitting

原题指路:https://codeforces.com/problemset/problem/870/C

题意 ( 2   s 2\ \mathrm{s} 2 s)

t    ( 1 ≤ t ≤ 1 e 5 ) t\ \ (1\leq t\leq 1\mathrm{e}5) t  (1t1e5)组测试数据.每组测试数据输入一个整数 n    ( 1 ≤ n ≤ 1 e 9 ) n\ \ (1\leq n\leq 1\mathrm{e}9) n  (1n1e9),将 n n n分解为尽量多个合数之和,输出合数的个数;无解输出 − 1 -1 1.

思路

先求出 [ 1 , 16 ] [1,16] [1,16]内的数的方案数,对 > 16 >16 >16的数,显然最优策略是拆出若干个 4 4 4,将其减小为 ≤ 16 \leq 16 16的数.

代码

const int MAXN = 20;
int ans[MAXN] = { 0,-1,-1,-1,1,-1,1,-1,2,1,2,-1,3,2,3,2,4 };

void solve() {
	int n; cin >> n;

    if (n <= 16) cout << ans[n] << endl;
    else {
        int tmp = (n - 16) / 4 + 1;
        cout << tmp + ans[n - 4 * tmp] << endl;
    }
}

int main() {
	CaseT  // 单测时注释掉该行
	solve();
}


876B. Divisiblity of Differences

原题指路:https://codeforces.com/problemset/problem/876/B

题意

给定 n n n个数 a 1 , ⋯   , a n    ( 0 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (0\leq a_i\leq 1\mathrm{e}9) a1,,an  (0ai1e9),从中选出 m    ( 1 ≤ m ≤ 1 e 5 ) m\ \ (1\leq m\leq 1\mathrm{e}5) m  (1m1e5)个元素,使得其中任意两元素之差是 k    ( 2 ≤ k ≤ n ≤ 1 e 5 ) k\ \ (2\leq k\leq n\leq 1\mathrm{e}5) k  (2kn1e5)的倍数,若有解,第一行输出"Yes",第二行输出任意方案;否则输出"No".

思路

将所有数按模 k k k的余数分类,输出任一元素个数 ≥ m \geq m m的类中的 m m m个元素即可.

代码

const int MAXN = 1e5 + 5;
vi nums[MAXN];

void solve() {
  int n, m, k; cin >> n >> m >> k;
  while (n--) {
    int a; cin >> a;
    nums[a % k].push_back(a);
  }

  for (int i = 0; i < MAXN; i++) {
    if (nums[i].size() >= m) {
      cout << "Yes" << endl;
      for (int j = 0; j < m; j++) cout << nums[i][j] << ' ';
      return;
    }
  }
  cout << "No" << endl;
}

int main() {
  solve();
}


891A. Pride

原题指路:https://codeforces.com/problemset/problem/891/A

题意 ( 2   s 2\ \mathrm{s} 2 s)

给定一个长度为 n    ( 1 ≤ n ≤ 2000 ) n\ \ (1\leq n\leq 2000) n  (1n2000)的序列 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).现有操作:选定 a [ ] a[] a[]中两相邻的元素 x , y x,y x,y,将它们之一替换为 gcd ⁡ ( x , y ) \gcd(x,y) gcd(x,y).若经若干次操作可将 a [ ] a[] a[]的元素都变为 1 1 1,输出最小步数;否则输出 − 1 -1 1.

思路

①若初始时序列中有 1 1 1,设 1 1 1的个数为 c n t cnt cnt,显然 a n s = n − c n t ans=n-cnt ans=ncnt.

②若初始时序列中无 1 1 1, O ( n 2 ) O(n^2) O(n2)暴力找是否存在一段区间$[l,r]\ s.t.\ 其中元素的 其中元素的 其中元素的\gcd=1 , 若存在 , 则 ,若存在,则 ,若存在,ans=(r-l)+(n-1) . 枚举起点 .枚举起点 .枚举起点l$即可.

代码

void solve() {
  int n; cin >> n;
  vi a(n + 1);
  int cnt = 0;  // 1的个数
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
    cnt += a[i] == 1;
  }

  if (cnt) {
    cout << n - cnt;
    return;
  }

  int ans = INF;
  for (int i = 1; i <= n; i++) {
    int g = a[i];  // gcd
    for (int j = i + 1; j <= n; j++) {
      g = gcd(g, a[j]);

      if (g == 1) {
        ans = min(ans, j - i + n - 1);
        break;
      }
    }
  }
  cout << (ans == INF ? -1 : ans);
}

int main() {
  solve();
}


900B. Position in Fraction

原题指路:https://codeforces.com/problemset/problem/900/B

题意

给定三个整数 a , b , c    ( 1 ≤ a < b ≤ 1 e 5 , 0 ≤ c ≤ 9 ) a,b,c\ \ (1\leq a< b\leq 1\mathrm{e}5,0\leq c\leq 9) a,b,c  (1a<b1e5,0c9),求分数 a b \dfrac{a}{b} ba的十进制表示中数码 c c c在小数点后第一次出现的位数,下标从 1 1 1开始,无解输出 − 1 -1 1.

思路

分数是有限或无限循环小数,显然循环节不超过 b b b,模拟前 b b b次除法即可.

代码

void solve() {
  int a, b, c; cin >> a >> b >> c;

  int cur = a;
  for (int i = 1; i <= b; i++) {
    cur *= 10;
    int tmp = cur / b;
    if (tmp == c) {
      cout << i;
      return;
    }

    cur %= b;
  }
  cout << -1;
}

int main() {
  solve();
}


912B. New Year’s Eve

原题指路:https://codeforces.com/problemset/problem/912/B

题意

给定两整数 n , k    ( 1 ≤ k ≤ n ≤ 1 e 18 ) n,k\ \ (1\leq k\leq n\leq 1\mathrm{e}18) n,k  (1kn1e18),从 [ 1 , n ] [1,n] [1,n]中选至多 k k k个数使得它们异或之和最大,输出最大异或和.

思路

k = 1 k=1 k=1时,显然 a n s = n ans=n ans=n.

k ≥ 2 k\geq 2 k2时,设 n n n的MSB为第 p p p位(下标从 0 0 0开始),则 a n s ≤ 2 p − 1 ans\leq 2^p-1 ans2p1.

​ 注意到 2 p   x o r   2 p − 1 = 2 p + 1 − 1 2^p\ \mathrm{xor}\ 2^p-1=2^{p+1}-1 2p xor 2p1=2p+11,故取不大于 n n n 2 p 2^p 2p 2 p − 1 2^p-1 2p1时异或和最大.

​ 可遍历 n n n的二进制数位求 p p p再求答案,也可用若干次 × 2 + 1 \times 2+1 ×2+1实现.

代码

void solve() {
  ll n, k; cin >> n >> k;

  if (k == 1) cout << n;
  else {
    ll ans = 1;
    while (ans < n) ans = ans * 2 + 1;
    cout << ans;
  }
}

int main() {
  solve();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值