[Codeforces] number theory (R1200) Part.5
题单:https://codeforces.com/problemset/page/6?tags=number%20theory,0-1200
1068B. LCM
原题指路:https://codeforces.com/problemset/problem/1068/B
题意
给定一个整数 b ( 1 ≤ b ≤ 1 e 10 ) b\ \ (1\leq b\leq 1\mathrm{e}10) b (1≤b≤1e10).对每个 a ∈ [ 1 , 1 e 18 ] a\in[1,1\mathrm{e}18] a∈[1,1e18],求 l c m ( a , b ) a \dfrac{\mathrm{lcm}(a,b)}{a} alcm(a,b)中有多少个相异的数.
思路
因原式中分子分母都含变量 a a a,考虑将一个变为常数 b b b.注意到 l c m ( a , b ) a = b gcd ( a , b ) \dfrac{\mathrm{lcm}(a,b)}{a}=\dfrac{b}{\gcd(a,b)} alcm(a,b)=gcd(a,b)b,则相异的数的个数即 b b b的不同的约数的个数,试除法求即可,时间复杂度 O ( b ) O(\sqrt{b}) O(b).
代码
void solve() {
ll b; cin >> b;
int ans = 0;
for (int i = 1; i <= b / i; i++)
if (b % i == 0) ans += 1 + (i != b / i);
cout << ans;
}
int main() {
solve();
}
1076B. Divisor Subtraction
原题指路:https://codeforces.com/problemset/problem/1076/B
题意 ( 2 s 2\ \mathrm{s} 2 s)
给定一个整数 n ( 2 ≤ n ≤ 1 e 10 ) n\ \ (2\leq n\leq 1\mathrm{e}10) n (2≤n≤1e10),进行如下操作:
①若 n = 0 n=0 n=0,操作结束.
② n n n减去其最小素因子,执行步骤①.
求减法的进行次数.
思路
①若 n n n是偶数,则其最小素因子为 2 2 2,显然 a n s = 2 n ans=\dfrac{2}{n} ans=n2.
②若 n n n是奇数,则它的最小素因子 d d d是奇数,减去一次后 n n n变为偶数,转化为情况①,故 a n s = 1 + n − d 2 ans=1+\dfrac{n-d}{2} ans=1+2n−d.
代码
ll get(ll x) { // 求x的最小素因子
for (ll i = 2; i <= x / i; i++)
if (x % i == 0) return i;
return x;
}
void solve() {
ll n; cin >> n;
cout << (n & 1 ? 1 + (n - get(n)) / 2 : n / 2);
}
int main() {
solve();
}
1107B. Digital root
原题指路:https://codeforces.com/problemset/problem/1107/B
题意
对一个非负整数,定义其digital root为一直求其各数位的和直至得到一个一位数.记数 x x x的digital root为 S ( x ) S(x) S(x),则 S ( 5 ) = 5 , S ( 38 ) = S ( 3 + 8 = 11 ) = S ( 1 + 1 = 2 ) = 2 , S ( 10 ) = S ( 1 + 0 = 1 ) = 1 S(5)=5,S(38)=S(3+8=11)=S(1+1=2)=2,S(10)=S(1+0=1)=1 S(5)=5,S(38)=S(3+8=11)=S(1+1=2)=2,S(10)=S(1+0=1)=1.
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据输入两个整数 k , x ( 1 ≤ k ≤ 1 e 12 , 1 ≤ x ≤ 9 ) k,x\ \ (1\leq k\leq 1\mathrm{e}12,1\leq x\leq 9) k,x (1≤k≤1e12,1≤x≤9),求第 k k k个digital root为 x x x的正整数.
思路
注意到 a k a k − 1 ⋯ a 1 ‾ = a 1 + a 2 ⋅ 10 + a 3 ⋅ 1 0 2 + ⋯ + a k ⋅ 1 0 k − 1 \overline{a_ka_{k-1}\cdots a_1}=a_1+a_2\cdot 10+a_3\cdot 10^2+\cdots+a_k\cdot 10^{k-1} akak−1⋯a1=a1+a2⋅10+a3⋅102+⋯+ak⋅10k−1,而 1 0 a m o d 9 = 1 10^a\ \mathrm{mod}\ 9=1 10a mod 9=1,则 a k a k − 1 ⋯ a 1 ‾ ≡ a 1 + a 2 + ⋯ + a k ( m o d 9 ) \overline{a_ka_{k-1}\cdots a_1}\equiv a_1+a_2+\cdots+a_k\ \ (\mathrm{mod}\ 9) akak−1⋯a1≡a1+a2+⋯+ak (mod 9),而digital root的定义是重复若干次该操作直至得到一个一位数,则数 x x x的digital root即 ( x − 1 ) m o d 9 + 1 (x-1)\ \mathrm{mod}\ 9+1 (x−1) mod 9+1,故 a n s = 9 ( k − 1 ) + x ans=9(k-1)+x ans=9(k−1)+x.
代码
void solve() {
ll k; int x; cin >> k >> x;
cout << (k - 1) * 9 + x << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1108B. Divisors of Two Integers
原题指路:https://codeforces.com/problemset/problem/1108/B
题意
将两个正整数 x , y x,y x,y的所有因数组成一个列表,若某数同为 x x x和 y y y的因数,则它在列表中出现两次.
给定一个长度为 n ( 2 ≤ n ≤ 128 ) n\ \ (2\leq n\leq 128) n (2≤n≤128)的打乱的列表 d 1 , ⋯ , d n ( 1 ≤ d i ≤ 1 e 4 ) d_1,\cdots,d_n\ \ (1\leq d_i\leq 1\mathrm{e}4) d1,⋯,dn (1≤di≤1e4).求该列表对应的 x x x和 y y y.数据保证有解.
思路
显然列表中的最大数是答案之一,将其的所有因数删去后,剩下的数中的最大值即答案之二.
代码
void solve() {
int n; cin >> n;
multiset<int> s;
for (int i = 0; i < n; i++) {
int x; cin >> x;
s.insert(x);
}
int ans = *prev(s.end());
for (int i = 1; i <= ans; i++)
if (ans % i == 0) s.erase(s.find(i));
cout << ans << ' ' << *prev(s.end());
}
int main() {
solve();
}
1133B. Preparation for International Women’s Day
原题指路:https://codeforces.com/problemset/problem/1133/B
题意 ( 2 s 2\ \mathrm{s} 2 s)
给定 n ( 1 ≤ n ≤ 2 e 5 ) n\ \ (1\leq n\leq 2\mathrm{e}5) n (1≤n≤2e5)个数 d 1 , ⋯ , d n ( 1 ≤ d i ≤ 1 e 9 ) d_1,\cdots,d_n\ \ (1\leq d_i\leq 1\mathrm{e}9) d1,⋯,dn (1≤di≤1e9),问从中至多能选出多少个数(偶数个),将它们分成若干个数对后每个数对的数之和都能整除 k ( 1 ≤ k ≤ 100 ) k\ \ (1\leq k\leq 100) k (1≤k≤100).
思路
显然只需将数按模 k k k的余数分类即可.注意单独计算余数为 0 0 0的情况和 k k k为偶数时余数为 k 2 \dfrac{k}{2} 2k的情况.
代码
void solve() {
int n, k; cin >> n >> k;
vi cnt(k); // cnt[i]表示模k余数为i的数的个数
while (n--) {
int x; cin >> x;
cnt[x % k]++;
}
int ans = cnt[0] / 2;
if (k % 2 == 0) ans += cnt[k / 2] / 2;
for (int i = 1; i < (k + 1) / 2; i++) ans += min(cnt[i], cnt[k - i]);
cout << ans * 2;
}
int main() {
solve();
}
1143B. Nirvana
原题指路:https://codeforces.com/problemset/problem/1143/B
题意
给定一个整数 n ( 1 ≤ n ≤ 2 e 9 ) n\ \ (1\leq n\leq 2\mathrm{e}9) n (1≤n≤2e9),求 [ 1 , n ] [1,n] [1,n]中的整数中每个数位之积的最大值.
思路
显然应让数的结尾有尽量多的 9 9 9,即若 n = a 0 a 1 ⋯ a l ‾ n=\overline{a_0a_1\cdots a_l} n=a0a1⋯al,则取得数位之积的最大值的数有形式 a 0 a 1 ⋯ a k ( a k + 1 − 1 ) 9 ⋯ 9 ‾ \overline{a_0a_1\cdots a_k(a_{k+1}-1)9\cdots 9} a0a1⋯ak(ak+1−1)9⋯9,枚举分界点,分别求答案后取 max \max max即可.
代码
int get_num(string s) { // 字符串转数字
int res = 0;
for (auto ch : s) res = res * 10 + (ch & 15);
return res;
}
int get_product(int x) { // 求数位之积
string s = to_string(x);
int res = 1;
for (auto ch : s) res *= ch & 15;
return res;
}
void solve() {
int n; cin >> n;
string s = to_string(n);
int ans = n;
for (int i = 0; i < s.size(); i++) { // 枚举分界点
if (s[i] == '0') continue;
string cur = s;
cur[i]--;
for (int j = i + 1; j < s.size(); j++) cur[j] = '9';
int num = get_num(cur);
if (num >= 1 && get_product(ans) < get_product(num)) ans = num;
}
cout << get_product(ans);
}
int main() {
solve();
}
1149A. Prefix Sum Primes
原题指路:https://codeforces.com/problemset/problem/1149/A
题意
给定一个长度为 n ( 1 ≤ n ≤ 2 e 5 ) n\ \ (1\leq n\leq 2\mathrm{e}5) n (1≤n≤2e5)的序列 a 1 , ⋯ , a n ( a i ∈ { 1 , 2 } ) a_1,\cdots,a_n\ \ (a_i\in\{1,2\}) a1,⋯,an (ai∈{1,2}),求一个排列使得其前缀和数组中素数的个数最多,输出任一符合的排列.
思路
因除 2 2 2外的素数都是奇数,故若初始序列非全 1 1 1或全 2 2 2,则可以 2 , 1 2,1 2,1开始,先放完剩下的 2 2 2,再放完剩下的 1 1 1,显然这是最优的.
代码
void solve() {
int n; cin >> n;
vi cnt(3);
for (int i = 0; i < n; i++) {
int a; cin >> a;
cnt[a]++;
}
if (cnt[1] == n)
for (int i = 0; i < n; i++) cout << 1 << ' ';
else if (cnt[2] == n)
for (int i = 0; i < n; i++) cout << 2 << ' ';
else {
cout << "2 1 ";
cnt[2]--, cnt[1]--;
while (cnt[2]--) cout << 2 << ' ';
while (cnt[1]--) cout << 1 << ' ';
}
}
int main() {
solve();
}
1166B. All the Vowels Please
原题指路:https://codeforces.com/problemset/problem/1166/B
题意
给定一个整数 k ( 1 ≤ k ≤ 1 e 4 ) k\ \ (1\leq k\leq 1\mathrm{e}4) k (1≤k≤1e4),对长度为 k k k的单词,问能否将其每个字母依次从上到下逐行填入一个 n × m n\times m n×m矩阵,使得每行和每列中五个元音字母都至少出现一次,若有解,输出任一符合条件的单词;否则输出 − 1 -1 −1.
思路
显然有解的充要条件是 n , m ≥ 5 n,m\geq 5 n,m≥5,且最优策略是只用五个元音字母,将它们依次填入.注意将 n , m n,m n,m中的较大者作为矩阵的行数.
代码
void solve() {
int k; cin >> k;
int n = -1, m = -1;
for (int i = 5; i <= k / i; i++) {
if (k % i == 0 && k / i >= 5) {
n = i, m = k / i;
break;
}
}
if (n == -1 && m == -1) cout << -1;
else {
string pattern = "aeiou";
string ans(k, ' ');
for (int i = 0; i < m; i++) // 先枚举大的
for (int j = 0; j < n; j++) ans[i * n + j] = pattern[(i + j) % 5];
cout << ans;
}
}
int main() {
solve();
}
1184A1. Heidi Learns Hashing (Easy)
原题指路:https://codeforces.com/problemset/problem/1184/A1
题意
给定一个整数 r ( 1 ≤ r ≤ 1 e 12 ) r\ \ (1\leq r\leq 1\mathrm{e}12) r (1≤r≤1e12),问是否存在一个正整数对 ( x , y ) s . t . x 2 + 2 x y + x + 1 = r (x,y)\ s.t.\ x^2+2xy+x+1=r (x,y) s.t. x2+2xy+x+1=r,若存在,输出 x x x最小的一对;否则输出"NO".
思路I
注意到若有解,则 x ≤ r x\leq \sqrt{r} x≤r,故枚举 x ∈ [ 1 , 1 e 6 ] x\in[1,1\mathrm{e}6] x∈[1,1e6],检查是否存在对应的 y y y即可.
代码I
void solve() {
ll r; cin >> r;
for (int x = 1; x <= 1e6; x++) {
ll tmp = r - (ll)x * x - x - 1;
if (tmp % (2 * x) || tmp / (2 *x) < 1) continue;
cout << x << ' ' << tmp / (2 * x);
return;
}
cout << "NO";
}
int main() {
solve();
}
思路II
在 r = x 2 + 2 x y + x + 1 r=x^2+2xy+x+1 r=x2+2xy+x+1中,显然影响 r r r的奇偶性的只有 x 2 + x + 1 x^2+x+1 x2+x+1.注意到不管 x x x取奇数还是偶数, r r r都是奇数,故 r r r为偶数时无解.令 x = 1 x=1 x=1,解得 y = r − 3 2 y=\dfrac{r-3}{2} y=2r−3,故 r ≥ 5 r\geq 5 r≥5时有解,且 x x x最小的解为 ( 1 , r − 3 2 ) \left(1,\dfrac{r-3}{2}\right) (1,2r−3).
代码II
void solve() {
ll r; cin >> r;
if (r < 5 || r % 2 == 0) cout << "NO";
else cout << 1 << ' ' << (r - 3) / 2;
}
int main() {
solve();
}
1238A. Prime Subtraction
原题指路:https://codeforces.com/problemset/problem/1238/A
题意 ( 2 s 2\ \mathrm{s} 2 s)
给定两整数 x , y x,y x,y.现有操作:令 x x x减去一个素数 p p p.问若干次操作后能否将 x x x变为 y y y,若能则输出"YES";否则输出"NO".
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据输入两个整数 x , y ( 1 ≤ y < x ≤ 1 e 18 ) x,y\ \ (1\leq y<x\leq 1\mathrm{e}18) x,y (1≤y<x≤1e18).
思路
设 d = x − y d=x-y d=x−y.
①若 d = 1 d=1 d=1,显然无法操作.
②若 d d d是偶数,即 x x x和 y y y奇偶时,可通过减若干次素数 2 2 2将 x x x变为 y y y.,
③若 d d d是奇数且 d ≥ 3 d\geq 3 d≥3,即 x x x和 y y y不同奇偶时,可先减一次素数 3 3 3,再减若干次素数 2 2 2将 x x x变为 y y y.
代码
void solve() {
ll x, y; cin >> x >> y;
cout << (x - y == 1 ? "NO" : "YES") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}