[Codeforces] number theory (R1200) Part.7
题单:https://codeforces.com/problemset/page/6?tags=number%20theory,0-1200
1389A. LCM Problem
原题指路:https://codeforces.com/problemset/problem/1389/A
题意 ( 2 s 2\ \mathrm{s} 2 s)
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据输入两个整数 l , r ( 1 ≤ l < r ≤ 1 e 9 ) l,r\ \ (1\leq l<r\leq 1\mathrm{e}9) l,r (1≤l<r≤1e9),问是否 ∃ x , y ∈ Z s . t . l ≤ x < y ≤ r , l ≤ l c m ( x , y ) ≤ r \exist x,y\in\mathbb{Z}\ s.t.\ \ l\leq x<y\leq r,l\leq \mathrm{lcm}(x,y)\leq r ∃x,y∈Z s.t. l≤x<y≤r,l≤lcm(x,y)≤r,若存在,输出任一组满足的 x , y x,y x,y;否则输出 − 1 − 1 -1\ -1 −1 −1.
思路
显然最优策略是取 l l l和 2 l 2l 2l,则有解的充要条件是: r ≥ 2 l r\geq 2l r≥2l.
代码
void solve() {
int l, r; cin >> l >> r;
if (r < 2 * l) cout << "-1 -1" << endl;
else cout << l << ' ' << 2 * l << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1409C. Yet Another Array Restoration
原题指路:https://codeforces.com/problemset/problem/1409/C
题意
有一个包含 n n n个正整数的序列.已知其中 ∃ \exists ∃两元素 x , y s . t . x < y x,y\ s.t.\ x<y x,y s.t. x<y,且将该序列升序排列后是个等差数列.给定 x , y x,y x,y,构造一个 max { a 1 , ⋯ , a n } \max\{a_1,\cdots,a_n\} max{a1,⋯,an}最小的满足条件的序列.
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据第一行输入三个整数 n , x , y ( 2 ≤ n ≤ 50 , 1 ≤ x < y ≤ 50 ) n,x,y\ \ (2\leq n\leq 50,1\leq x<y\leq 50) n,x,y (2≤n≤50,1≤x<y≤50).
对每组测试数据,输出一个长度为 n n n的满足条件的序列 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
显然等差数列的公差 d d d是 y − x y-x y−x的约数.添加元素 y , y − d , y − 2 d , ⋯ y,y-d,y-2d,\cdots y,y−d,y−2d,⋯直至够 n n n个元素或下一个元素 < 1 <1 <1,检查 x x x是否在序列中,若在则该公差符合要求.若此时仍不足 n n n个元素,添加元素 y + d , y + 2 d , ⋯ y+d,y+2d,\cdots y+d,y+2d,⋯直至够 n n n个元素,更新答案即可.时间复杂度 O ( n y − x ) O(n\sqrt{y-x}) O(ny−x).
代码I
void solve() {
int n, x, y; cin >> n >> x >> y;
vi ans;
for (int d = 1; d <= y - x; d++) {
if ((y - x) % d) continue;
vi res;
bool foundx = false; // 记录x是否在序列中
int need = n; // 记录当前序列还差多少个元素
int cur = y; // 当前元素
while (cur >= 1 && need) {
res.push_back(cur);
foundx |= cur == x;
cur -= d;
need--;
}
cur = y;
while (need > 0) { // 注意此处不能写while(need--),否则下面的!need不满足
cur += d;
res.push_back(cur);
need--;
}
sort(all(res));
if (!need && foundx)
if (ans.empty() || ans.back() > res.back()) ans = res;
}
for (auto i : ans) cout << i << ' ';
cout << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
思路II
枚举公差 d d d,考虑直接求出首项.设首项 a 1 = y − k d ≥ 1 a_1=y-kd\geq 1 a1=y−kd≥1,解得 k ≤ ⌊ y − 1 d ⌋ k\leq\left\lfloor\dfrac{y-1}{d}\right\rfloor k≤⌊dy−1⌋.为保证 y y y在序列中,则 y y y至多是等差数列的第 n n n项,则 k ≤ n − 1 k\leq n-1 k≤n−1.
代码II
void solve() {
int n, x, y; cin >> n >> x >> y;
int diff = y - x;
for (int d = 1; d <= diff; d++) {
if (diff % d) continue;
if (diff / d > n - 1) continue;
int k = min((y - 1) / d, n - 1);
int a1 = y - k * d;
for (int i = 0; i < n; i++) cout << a1 + i * d << " \n"[i == n - 1];
break;
}
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1411B. Fair Numbers
原题指路:https://codeforces.com/problemset/problem/1411/B
题意
称一个正整数是fair的,如果它能被其所有非零数码整除.
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据输入一个整数 n ( 1 ≤ n ≤ 1 e 18 ) n\ \ (1\leq n\leq 1\mathrm{e}18) n (1≤n≤1e18).求 ≥ n \geq n ≥n的最小的一个fair的数.
思路
称一个正整数是super fair的,如果它能被 1 ∼ 9 1\sim 9 1∼9这 9 9 9个数码整除.显然super fair的数是 2520 2520 2520的倍数.
显然答案不超过 ≥ n \geq n ≥n的最小的super fair的数,暴力求即可.
代码
bool check(ll x) {
string s = to_string(x);
for (auto ch : s)
if (ch != '0' && x % (ch & 15)) return false;
return true;
}
void solve() {
ll n; cin >> n;
for (int i = 0; i < 2520; i++) {
if (check(n)) {
cout << n << endl;
return;
}
n++;
}
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1455A. Strange Functions
原题指路:https://codeforces.com/problemset/problem/1455/A
题意 ( 2 s 2\ \mathrm{s} 2 s)
对正整数 x x x,定义函数 f ( x ) f(x) f(x)表示将 x x x的十进制表示反转并去掉前导零得到的数字,如 f ( 321 ) = 123 , f ( 120 ) = 21 f(321)=123,f(120)=21 f(321)=123,f(120)=21.定义函数 g ( x ) = x f ( f ( x ) ) g(x)=\dfrac{x}{f(f(x))} g(x)=f(f(x))x.给定一个正整数 n n n,对 [ 1 , n ] [1,n] [1,n]中的任意整数 x x x,问 g ( x ) g(x) g(x)有多少种不同的取值.
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据输入一个整数 n ( 1 ≤ n < 1 e 100 ) n\ \ (1\leq n<1\mathrm{e}100) n (1≤n<1e100).
思路
注意到 x = 1 x=1 x=1是最小的使得 g ( x ) = 1 g(x)=1 g(x)=1的数, x = 10 x=10 x=10是最小的使得 g ( x ) = 10 g(x)=10 g(x)=10的数, x = 100 x=100 x=100是最小的使得 g ( x ) = 100 g(x)=100 g(x)=100的数,故答案即 n n n的十进制表示(无前导零)的长度.
代码
void solve() {
string s; cin >> s;
cout << s.length() << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1471A. Strange Partition
原题指路:https://codeforces.com/problemset/problem/1471/A
题意
给定一个长度为 n n n的序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an.现有如下操作:将两相邻元素替换为它们之和,注意每次操作后序列长度 − 1 -1 −1.对给定的整数 x x x,定义序列的值为 ∑ i = 1 k ⌈ a i x ⌉ \displaystyle \sum_{i=1}^k \left\lceil\dfrac{a_i}{x}\right\rceil i=1∑k⌈xai⌉.问经过若干次(可能为零次)操作后给定序列的值最小和最大分别能取到多少.
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据第一行输入两个整数 n , x ( 1 ≤ n ≤ 1 e 5 , 1 ≤ x ≤ 1 e 9 ) n,x\ \ (1\leq n\leq 1\mathrm{e}5,1\leq x\leq 1\mathrm{e}9) n,x (1≤n≤1e5,1≤x≤1e9).第二行输入 n n n个整数 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).数据保证所有测试数据的 n n n之和不超过 1 e 5 1\mathrm{e}5 1e5.
思路
注意到 ⌈ a + b x ⌉ ≤ ⌈ a x ⌉ + ⌈ b x ⌉ \left\lceil\dfrac{a+b}{x}\right\rceil\leq \left\lceil\dfrac{a}{x}\right\rceil+\left\lceil\dfrac{b}{x}\right\rceil ⌈xa+b⌉≤⌈xa⌉+⌈xb⌉,故不做任何操作时取得最大值,做 ( n − 1 ) (n-1) (n−1)次操作时取得最小值.
代码
void solve() {
int n, x; cin >> n >> x;
vi a(n);
ll ans1 = 0, ans2 = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
ans1 += ceil((double)a[i] / x);
ans2 += a[i];
}
ans2 = ceil((double)ans2 / x);
cout << ans2 << ' ' << ans1 << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1473B. String LCM
原题指路:https://codeforces.com/problemset/problem/1473/B
题意 ( 2 s ) (2\ \mathrm{s}) (2 s)
定义字符串 x x x与正整数 a a a的乘法 a ⋅ x a\cdot x a⋅x表示将 x x x重复 a a a次.称字符串 a a a能被字符串 b b b整除,如果 ∃ x ∈ Z + s . t . b ⋅ x = a \exists x\in\mathbb{Z}^+\ s.t.\ b\cdot x=a ∃x∈Z+ s.t. b⋅x=a.定义字符串 s s s和 t t t的LCM为能整除 s s s和 t t t的最短的非空字符串,记作 l c m ( s , t ) \mathrm{lcm}(s,t) lcm(s,t).可以证明若 l c m ( s , t ) \mathrm{lcm}(s,t) lcm(s,t)存在,则它唯一.
有 t ( 1 ≤ t ≤ 2000 ) t\ \ (1\leq t\leq 2000) t (1≤t≤2000)组测试数据.每组测试数据输入两行分别表示只包含小写英文字母的字符串 s s s和 t ( 1 ≤ ∣ s ∣ , ∣ t ∣ ≤ 20 ) t\ \ (1\leq |s|,|t|\leq 20) t (1≤∣s∣,∣t∣≤20).
对每组测试数据,若 l c m ( s , t ) \mathrm{lcm}(s,t) lcm(s,t)存在,输出 l c m ( s , t ) \mathrm{lcm}(s,t) lcm(s,t);否则输出 − 1 -1 −1.
思路
注意到若字符串 x x x是字符串 y y y的倍数,则 ∣ x ∣ |x| ∣x∣是 ∣ y ∣ |y| ∣y∣的倍数.显然若 l c m ( s , t ) \mathrm{lcm}(s,t) lcm(s,t)存在,则 ∣ l c m ( s , t ) ∣ = l c m ( ∣ s ∣ , ∣ t ∣ ) |\mathrm{lcm}(s,t)|=\mathrm{lcm}(|s|,|t|) ∣lcm(s,t)∣=lcm(∣s∣,∣t∣),只需检查 l c m ( ∣ s ∣ , ∣ t ∣ ) ∣ s ∣ ⋅ s \dfrac{\mathrm{lcm(|s|,|t|)}}{|s|}\cdot s ∣s∣lcm(∣s∣,∣t∣)⋅s与 l c m ( ∣ s ∣ , ∣ t ∣ ) ∣ t ∣ ⋅ t \dfrac{\mathrm{lcm(|s|,|t|)}}{|t|}\cdot t ∣t∣lcm(∣s∣,∣t∣)⋅t是否相等即可.
代码
string get(int a, string x) {
string res;
while (a--) res += x;
return res;
}
void solve() {
string s, t; cin >> s >> t;
int n = s.length(), m = t.length();
int d = gcd(n, m);
cout << (get(m / d, s) == get(n / d, t) ? get(m / d, s) : "-1") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1474B. Different Divisors
原题指路:https://codeforces.com/problemset/problem/1474/B
题意
有 t ( 1 ≤ t ≤ 3000 ) t\ \ (1\leq t\leq 3000) t (1≤t≤3000)组测试数据.每组测试数据输入一个整数 d ( 1 ≤ d ≤ 1 e 4 ) d\ \ (1\leq d\leq 1\mathrm{e}4) d (1≤d≤1e4),求一个最小的正整数 a a a满足下列条件:① a a a至少有四个约数;② a a a的任意两约数之差 ≥ d \geq d ≥d.
思路
为使得 a a a最小,显然 a a a有且只有 4 4 4个约数,此时 a a a有形式 a = p 3 a=p^3 a=p3或 a = p q a=pq a=pq,其中 p , q ∈ p r i m e s p,q\in primes p,q∈primes.
① a = p 3 a=p^3 a=p3时, a a a有约数 1 , p , p 2 , p 3 1,p,p^2,p^3 1,p,p2,p3.
注意到 p ≥ 2 p\geq 2 p≥2时,有 p 3 − p 2 > p 2 − p > p − 1 p^3-p^2>p^2-p>p-1 p3−p2>p2−p>p−1,只需取最小的 p ≥ d + 1 p\geq d+1 p≥d+1即可.
② a = p q a=pq a=pq时, a a a有约数 1 , p , q , p q 1,p,q,pq 1,p,q,pq.不妨设 p < q p<q p<q.
取最小的 p ≥ d + 1 p\geq d+1 p≥d+1和最小的 q ≥ p + d q\geq p+d q≥p+d,此时 p q − q = q ( p − 1 ) ≥ q d > d pq-q=q(p-1)\geq qd>d pq−q=q(p−1)≥qd>d.
下面证明 ∄ p ′ , q ′ ∈ p r i m e s s . t . p ′ q ′ < p q \not\exist p',q'\in primes\ s.t.\ p'q'<pq ∃p′,q′∈primes s.t. p′q′<pq.
因 p p p是最小的 ≥ d + 1 \geq d+1 ≥d+1的素数,则 p ′ ≥ p p'\geq p p′≥p,同理 q ′ ≥ q q'\geq q q′≥q.故 p ′ q ′ ≥ p q p'q'\geq pq p′q′≥pq.
时间复杂度 O ( g a p ⋅ p r i m e c h e c k ) O(gap\cdot primecheck) O(gap⋅primecheck),其中 g a p gap gap为相邻两素数间的距离,平均为 O ( log a ) O(\log a) O(loga); p r i m e c h e c k primecheck primecheck为判断是否为素数的时间复杂度.
代码
void solve() {
int d; cin >> d;
vi primes;
for (int i = d + 1;; i++) { // 求≥d+1的最小素数p
bool flag = true; // 记录i是否为素数
for (int j = 2; j * j <= i; j++) {
if (i % j == 0) {
flag = false;
break;
}
}
if (flag) {
primes.push_back(i);
break;
}
}
for (int i = primes.back() + d;; i++) { // 求≥p+d的最小素数q
bool flag = true; // 记录i是否为素数
for (int j = 2; j * j <= i; j++) {
if (i % j == 0) {
flag = false;
break;
}
}
if (flag) {
primes.push_back(i);
break;
}
}
cout << min((ll)primes[0] * primes[1], (ll)primes[0] * primes[0] * primes[0]) << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1475A. Odd Divisor
原题指路:https://codeforces.com/problemset/problem/1475/A
题意 ( 2 s 2\ \mathrm{s} 2 s)
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据输入一个整数 n ( 2 ≤ n ≤ 1 e 14 ) n\ \ (2\leq n\leq 1\mathrm{e}14) n (2≤n≤1e14).若 n n n有奇约数,输出"YES";否则输出"NO".
思路
将 n n n素因数分解,则 n n n有奇约数的充要条件是: n n n有奇素因子.
注意到 2 2 2是唯一的偶素数,故 n n n无奇约数的充要条件是: n n n是 2 2 2的幂次.
代码
void solve() {
ll n; cin >> n;
cout << (n & (n - 1) ? "YES" : "NO") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1485A. Add and Divide
原题指路:https://codeforces.com/problemset/problem/1485/A
题意
给定两正整数 a , b a,b a,b.现有如下两种操作:① a = ⌊ a b ⌋ a=\left\lfloor\dfrac{a}{b}\right\rfloor a=⌊ba⌋;② b = b + 1 b=b+1 b=b+1.求将 a a a变为 0 0 0的最小操作次数.
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据输入两个整数 a , b ( 1 ≤ a , b ≤ 1 e 9 ) a,b\ \ (1\leq a,b\leq 1\mathrm{e}9) a,b (1≤a,b≤1e9).
思路
注意到 ⌊ a b + 1 ⌋ ≤ ⌊ a b ⌋ \left\lfloor\dfrac{a}{b+1}\right\rfloor\leq \left\lfloor\dfrac{a}{b}\right\rfloor ⌊b+1a⌋≤⌊ba⌋,则应先用操作②,即先将 b b b增大到某一值,再不断地用操作①直至 a = 0 a=0 a=0.注意特判 b < 2 b<2 b<2的情况.对 b ≥ 2 b\geq 2 b≥2的情况,至多需要 ⌊ log 2 a ⌋ ≤ 29 \left\lfloor\log_2 a\right\rfloor\leq29 ⌊log2a⌋≤29步即可使得 a = 0 a=0 a=0.
枚举用操作②的次数 i ∈ [ 0 , 30 ] i\in[0,30] i∈[0,30],对每个 i i i,求至少需用多少次操作①,更新答案即可.
时间复杂度 O ( log 2 a ) O(\log^2 a) O(log2a).
代码
void solve() {
ll A, B; cin >> A >> B;
ll ans = A + 3;
for (ll i = (B < 2 ? 2 - B : 0); i < ans; i++) {
ll a = A, b = B + i;
ll res = i;
while (a) {
a /= b;
res++;
}
ans = min(ans, res);
}
cout << ans << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1487B. Cat Cycle
原题指路:https://codeforces.com/problemset/problem/1487/B
题意
有编号 1 ∼ n 1\sim n 1∼n的 n n n个点围成一圈.初始时猫A在 n n n号点,猫B在 1 1 1号点.每个时刻两猫同时移动,其中猫A逆时针移动,猫B顺时针移动.若某时刻两猫移动到同一点处,则猫B逆时针多走一步到下一个点.求第 k k k个时刻时猫B所在的点的编号.
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据输入两个整数 n , k ( 2 ≤ n ≤ 1 e 9 , 1 ≤ k ≤ 1 e 9 ) n,k\ \ (2\leq n\leq 1\mathrm{e}9,1\leq k\leq 1\mathrm{e}9) n,k (2≤n≤1e9,1≤k≤1e9).
思路
①若 n n n为偶数,则不会出现两猫移动到同一点处的情况.
②若 n n n为奇数,则每 ⌊ n 2 ⌋ \left\lfloor\dfrac{n}{2}\right\rfloor ⌊2n⌋个时刻猫B会多走一步.因步数要对 n n n取模,不妨 k − − k-- k−−映射到下标从 0 0 0开始,最后 + 1 +1 +1即可.
代码
void solve() {
int n, k; cin >> n >> k;
cout << ((k - 1) + (n & 1) * ((k - 1) / (n / 2))) % n + 1 << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}