[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 (1≤n≤1e5)的序列 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 (1≤ai≤1e5)和一个整数 x ( 0 ≤ x ≤ 1 e 5 ) x\ \ (0\leq x\leq 1\mathrm{e}5) x (0≤x≤1e5).求使得 1 ≤ i < j ≤ n 1\leq i<j\leq n 1≤i<j≤n且 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 (1≤n≤1e4),求三个相异的整数 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 (1≤x,y,z≤1e9) 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,z≤1e9.
注意 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 (1≤n≤1e5)个数 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 (1≤ai≤1e5),从中取最多的数 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 (1≤n≤1e15,1≤k≤1e9),求 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 (1≤n≤2e5)的序列 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 (1≤ai,bi≤1e9).将序列 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=1∑nf(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) (n−i)个元素中选 ( k − 1 ) (k-1) (k−1)个元素,故 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=1∑n−k+1i⋅Cn−ik−1.
注意到 f ( n , k ) f ( n , k − 1 ) = k k + 1 \dfrac{f(n,k)}{f(n,k-1)}=\dfrac{k}{k+1} f(n,k−1)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 (1≤t≤1e5)组测试数据.每组测试数据输入一个整数 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.
思路
先求出 [ 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 (0≤ai≤1e9),从中选出 m ( 1 ≤ m ≤ 1 e 5 ) m\ \ (1\leq m\leq 1\mathrm{e}5) m (1≤m≤1e5)个元素,使得其中任意两元素之差是 k ( 2 ≤ k ≤ n ≤ 1 e 5 ) k\ \ (2\leq k\leq n\leq 1\mathrm{e}5) k (2≤k≤n≤1e5)的倍数,若有解,第一行输出"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 (1≤n≤2000)的序列 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).现有操作:选定 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=n−cnt.
②若初始时序列中无 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 (1≤a<b≤1e5,0≤c≤9),求分数 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 (1≤k≤n≤1e18),从 [ 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 k≥2时,设 n n n的MSB为第 p p p位(下标从 0 0 0开始),则 a n s ≤ 2 p − 1 ans\leq 2^p-1 ans≤2p−1.
注意到 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 2p−1=2p+1−1,故取不大于 n n n的 2 p 2^p 2p和 2 p − 1 2^p-1 2p−1时异或和最大.
可遍历 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();
}