[Codeforces] number theory (R1200) Part.8
题单:https://codeforces.com/problemset/page/6?tags=number%20theory,0-1200
1511B. GCD Length
原题指路:https://codeforces.com/problemset/problem/1511/B
题意 ( 2 s 2\ \mathrm{s} 2 s)
给定三个整数 a , b , c a,b,c a,b,c,构造任两个正整数 x , y s . t . x x,y\ s.t.\ x x,y s.t. x的十进制表示(不含前导零,下同)包含 a a a个数码, y y y的十进制表示包含 b b b个数码, gcd ( x , y ) \gcd(x,y) gcd(x,y)的十进制表示包含 c c c个数码.
有 t ( 1 ≤ t ≤ 285 ) t\ \ (1\leq t\leq 285) t (1≤t≤285)组测试数据.每组测试数据输入三个整数 a , b , c ( 1 ≤ a , b ≤ 9 , 1 ≤ c ≤ min { a , b } ) a,b,c\ \ (1\leq a,b\leq 9,1\leq c\leq \min\{a,b\}) a,b,c (1≤a,b≤9,1≤c≤min{a,b}).数据保证有解.
思路
令 x = 1 0 ⋯ 0 ⏟ ( a − c ) 个 0 ⋯ 0 ⏟ ( c − 1 ) 个 , y = 1 1 ⋯ 1 ⏟ ( b − c ) 个 0 ⋯ 0 ⏟ ( c − 1 ) 个 x=1\underbrace{0\cdots 0}_{(a-c)个}\underbrace{0\cdots 0}_{(c-1)个},y=1\underbrace{1\cdots 1}_{(b-c)个}\underbrace{0\cdots 0}_{(c-1)个} x=1(a−c)个 0⋯0(c−1)个 0⋯0,y=1(b−c)个 1⋯1(c−1)个 0⋯0.因 gcd ( 10 ⋯ 0 , 11 ⋯ 1 ) = 1 \gcd(10\cdots 0,11\cdots 1)=1 gcd(10⋯0,11⋯1)=1,故满足条件.
代码
void solve() {
int a, b, c; cin >> a >> b >> c;
cout << "1" << string(a - 1, '0') << ' ' << string(b - c + 1, '1') << string(c - 1, '0') << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1514A. Perfectly Imperfect Array
原题指路:https://codeforces.com/problemset/problem/1514/A
题意
称一个序列是好的,如果它存在一个非空的子列使得其中元素之积不是完全平方数.
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据第一行输入一个整数 n ( 1 ≤ n ≤ 100 ) n\ \ (1\leq n\leq 100) n (1≤n≤100),表示序列长度.第二行输入 n n n个整数 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 1 e 4 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}4) a1,⋯,an (1≤ai≤1e4).
对每组测试数据,若序列 a [ ] a[] a[]是好的,输出"YES";否则输出"NO".
思路
注意到若序列 a [ ] a[] a[]中包含一个非完全平方数,则它是好的.
代码
bool check(int x) {
int tmp = sqrt(x);
return x == tmp * tmp;
}
void solve() {
int n; cin >> n;
bool ok = false;
while (n--) {
int x; cin >> x;
ok |= !check(x);
}
cout << (ok ? "YES" : "NO") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1515B. Phoenix and Puzzle
原题指路:https://codeforces.com/problemset/problem/1515/B
题意 ( 2 s 2\ \mathrm{s} 2 s)
有 n n n个如图(1)所示的等腰直角三角形的拼图,问能否用它们拼成一个正方形,使得所有的拼图都用完,若能则输出"YES";否则输出"NO".
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据输入一个整数 n ( 1 ≤ n ≤ 1 e 9 ) n\ \ (1\leq n\leq 1\mathrm{e}9) n (1≤n≤1e9).
思路
如图(2)和图(3)所示,可用 2 2 2块或 4 4 4块拼图拼成一个小正方形.设小正方形的数量为 x x x,则用小正方先能拼成一个大正方形的充要条件是: x x x是完全平方数.
有解的条件只能是下列两条件之一:① n n n是 2 2 2的倍数,且 n 2 \dfrac{n}{2} 2n是完全平方数;② n n n是 4 4 4的倍数,且 n 4 \dfrac{n}{4} 4n是完全平方数.
[证] 下面证明无其他解.设直角三角形的直角边长为 1 1 1,则斜边长为 2 \sqrt{2} 2.
设拼成的大正方形的边长用到了 a a a条直角边和 b b b条斜边,则其边长为 a + 2 b a+\sqrt{2}b a+2b.
注意到大正方形的面积 ( a + 2 b ) 2 \left(a+\sqrt{2}b\right)^2 (a+2b)2是有理数,则 a = 0 a=0 a=0或 b = 0 b=0 b=0.
代码
bool check(int x) {
int tmp = sqrt(x);
return x == tmp * tmp;
}
void solve() {
int n; cin >> n;
bool ok = false;
ok |= n % 2 == 0 && check(n / 2);
ok |= n % 4 == 0 && check(n / 4);
cout << (ok ? "YES" : "NO") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1520B. Ordinary Numbers
原题指路:https://codeforces.com/problemset/problem/1520/B
题意 ( 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 ( 1 ≤ n ≤ 1 e 9 ) n\ \ (1\leq n\leq 1\mathrm{e}9) n (1≤n≤1e9),问 [ 1 , n ] [1,n] [1,n]中好的数的个数.
思路
注意到好的数可表示为 d ( 1 0 0 + 1 0 1 + ⋯ + 1 0 k ) d(10^0+10^1+\cdots+10^k) d(100+101+⋯+10k),则只需统计 s . t . d ( 1 0 0 + 1 0 1 + ⋯ + 1 0 k ) ≤ n \ s.t.\ d(10^0+10^1+\cdots+10^k)\leq n s.t. d(100+101+⋯+10k)≤n的整数对 ( d , k ) (d,k) (d,k)的个数,其中 d ∈ [ 1 , 9 ] , k ∈ [ 0 , 8 ] d\in[1,9],k\in[0,8] d∈[1,9],k∈[0,8],暴力统计即可.
代码
void solve() {
int n; cin >> n;
int ans = 0;
for (ll pow10 = 1; pow10 <= n; pow10 = pow10 * 10 + 1) {
for (int d = 1; d <= 9; d++)
ans += pow10 * d <= n;
}
cout << ans << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1521A. Nastia and Nearly Good Numbers
原题指路:https://codeforces.com/problemset/problem/1521/A
题意
给定两整数 A , B A,B A,B,①称一个整数是好的,如果它能被 A B AB AB整除;②称一个整数是近似好的,如果它能被 A A A整除.构造三个相异的正整数 x , y , z x,y,z x,y,z,使得其中恰有一个好的数、恰有两个近似好的数,且 x + y = z x+y=z x+y=z.
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据输入两个整数 A , B ( 1 ≤ A , B ≤ 1 e 6 ) A,B\ \ (1\leq A,B\leq 1\mathrm{e}6) A,B (1≤A,B≤1e6).
对每组测试数据,若有解,输出"YES"并输出满足条件的三个整数 x , y , z ( 1 ≤ x , y , z ≤ 1 e 18 ) x,y,z\ \ (1\leq x,y,z\leq 1\mathrm{e}18) x,y,z (1≤x,y,z≤1e18);否则输出"NO".
思路
① B = 1 B=1 B=1时,被 A B AB AB整除即被 A A A整除,此时好的和近似好的等价,无解.
② B ≥ 2 B\geq 2 B≥2时,取 A + A B = A ( B + 1 ) A+AB=A(B+1) A+AB=A(B+1).
代码
void solve() {
int a, b; cin >> a >> b;
if (b == 1) cout << "NO" << endl;
else {
cout << "YES" << endl;
cout << a << ' ' << (ll)a * b <<' ' << (ll)a * (b + 1) << endl;
}
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1525A. Potion-making
原题指路:https://codeforces.com/problemset/problem/1525/A
题意
有A和B两种水,现要配置包含 k % k\% k%的A水和 ( 100 − k ) % (100-k)\% (100−k)%的B水的水,每次操作可加 1 1 1单位的A水或B水,问最少操作次数.
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据输入一个整数 k ( 1 ≤ k ≤ 100 ) k\ \ (1\leq k\leq 100) k (1≤k≤100).
思路
首先必有解,最坏可加 k k k次A水和 ( 100 − k ) (100-k) (100−k)次B水.
设A水、B水分别加 x x x、 y y y次,则 x x + y = k 100 \dfrac{x}{x+y}=\dfrac{k}{100} x+yx=100k.显然 ( x + y ) ∣ 100 (x+y)\mid 100 (x+y)∣100,不妨设 z ( x + y ) = 100 z(x+y)=100 z(x+y)=100,则 z x = k zx=k zx=k,即 x = k z x=\dfrac{k}{z} x=zk.
代入 z ( x + y ) = 100 z(x+y)=100 z(x+y)=100,解得 y = 100 − k z y=\dfrac{100-k}{z} y=z100−k,则 a n s = x + y = 100 z ans=x+y=\dfrac{100}{z} ans=x+y=z100.
因 x , a n s ∈ Z x,ans\in\mathbb{Z} x,ans∈Z,则 z ∣ k , z ∣ 100 z\mid k,z\mid 100 z∣k,z∣100.为使得 a n s ans ans最小,取 z = gcd ( 100 , k ) z=\gcd(100,k) z=gcd(100,k).
代码
void solve() {
int k; cin >> k;
cout << 100 / gcd(100, k) << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1535B. Array Reodering
原题指路:https://codeforces.com/problemset/problem/1535/B
题意
对序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an称一对下标 ( i , j ) ( 1 ≤ i < j ≤ n ) (i,j)\ \ (1\leq i<j\leq n) (i,j) (1≤i<j≤n)是好的,如果 gcd ( a i , 2 a j ) > 1 \gcd(a_i,2a_j)>1 gcd(ai,2aj)>1.将 a [ ] a[] a[]排序,使得其好的下标的对数最多,输出好的下标的对数.
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据第一行输入一个整数 n ( 2 ≤ n ≤ 2000 ) n\ \ (2\leq n\leq 2000) n (2≤n≤2000).第二行输入 n n n个整数 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).数据保证所有测试数据的 n n n之和不超过 2000 2000 2000.
思路
显然应将偶数排在前面,奇数排在后面.显然偶数间顺序无关.对奇数 a i , a j , gcd ( a i , 2 a j ) = gcd ( a i , a j ) a_i,a_j,\gcd(a_i,2a_j)=\gcd(a_i,a_j) ai,aj,gcd(ai,2aj)=gcd(ai,aj),故奇数间的顺序无关.
代码
void solve() {
int n; cin >> n;
vi a(n);
for (int& ai : a) cin >> ai;
sort(all(a), [&](const int& A, const int& B) {
return A % 2 < B % 2;
});
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++)
ans += gcd(a[i], a[j] * 2) > 1;
}
cout << ans << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1541B. Pleasant Pairs
原题指路:https://codeforces.com/problemset/problem/1541/B
题意
给定一个包含 n n n个相异整数的序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an,求使得 1 ≤ i < j ≤ n 1\leq i<j\leq n 1≤i<j≤n且 a i ⋅ a j = i + j a_i\cdot a_j=i+j ai⋅aj=i+j的整数对 ( i , j ) (i,j) (i,j)的对数.
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据第一行输入一个整数 n ( 2 ≤ n ≤ 1 e 5 ) n\ \ (2\leq n\leq 1\mathrm{e}5) n (2≤n≤1e5).第二行输入 n n n个相异的整数 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 2 n ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 2n) a1,⋯,an (1≤ai≤2n).数据保证所有测试数据的 n n n之和不超过 2 e 5 2\mathrm{e}5 2e5.
思路
注意到 a i ⋅ a j = i + j ≤ 2 n a_i\cdot a _j=i+j\leq 2n ai⋅aj=i+j≤2n,可枚举每个 ( i + j ) (i+j) (i+j)的值后再枚举每个 a i a_i ai,检查是否存在满足条件的元素即可.
满足上述条件的整数对 ( i , j ) (i,j) (i,j)有 O ( n log n ) O(n\log n) O(nlogn)对.
[证] 设 a i = x a_i=x ai=x,则 a j a_j aj至多有 2 n x \dfrac{2n}{x} x2n种取值. ∑ i = 1 n 2 n i = 2 n ∑ i = 1 n 1 i = O ( n log n ) \displaystyle\sum_{i=1}^n \dfrac{2n}{i}=2n\sum_{i=1}^n \dfrac{1}{i}=O(n\log n) i=1∑ni2n=2ni=1∑ni1=O(nlogn).
代码
void solve() {
int n; cin >> n;
umap<int, int> pos; // 每个a_i的值所在的下标
for (int i = 1; i <= n; i++) {
int a; cin >> a;
pos[a] = i;
}
int ans = 0;
for (int i = 2; i <= 2 * n; i++) { // 枚举i+j
for (int j = 1; j * j < i; j++) { // 枚举a[i],注意不是<=
if (i % j == 0) {
int k = i / j;
if (pos[j] && pos[k] && pos[j] + pos[k] == i) ans++;
}
}
}
cout << ans << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1543A. Exciting Bets
原题指路:https://codeforces.com/problemset/problem/1543/A
题意
给定两正整数 a , b a,b a,b.现有两种操作:① a + + , b + + a++,b++ a++,b++;② a − − , b − − a--,b-- a−−,b−−,此操作当且仅当 a , b > 0 a,b>0 a,b>0时可执行.问经过若干次(可能为零次)操作后 gcd ( a , b ) \gcd(a,b) gcd(a,b)的最大值.
有 t ( 1 ≤ t ≤ 5000 ) t\ \ (1\leq t\leq 5000) t (1≤t≤5000)组测试数据.每组测试数据输入两个整数 a , b ( 0 ≤ a , b ≤ 1 e 18 ) a,b\ \ (0\leq a,b\leq 1\mathrm{e}18) a,b (0≤a,b≤1e18).
对每组测试数据,若 gcd ( a , b ) \gcd(a,b) gcd(a,b)可达到无穷大,则输出"0 0";否则先输出 gcd ( a , b ) \gcd(a,b) gcd(a,b)的最大值,再输出达到最大值所需的最小步数.
思路
① a = b a=b a=b时,一直做操作①即可使得 gcd ( a , b ) = I N F \gcd(a,b)=INF gcd(a,b)=INF.
②不妨设 a ≥ b a\geq b a≥b. gcd ( a , b ) \gcd(a,b) gcd(a,b)能取得的最大值是 a − b a-b a−b.
[证] 注意到 gcd ( a , b ) = gcd ( a − b , b ) \gcd(a,b)=\gcd(a-b,b) gcd(a,b)=gcd(a−b,b),其中 g = a − b g=a-b g=a−b在操作过程中不变,
为使得 gcd ( a , b ) \gcd(a,b) gcd(a,b)最大,应通过操作将 b b b变为 g g g的倍数.
≤ b \leq b ≤b的最大的 g g g的倍数是 ⌊ b g ⌋ ⋅ g \left\lfloor\dfrac{b}{g}\right\rfloor \cdot g ⌊gb⌋⋅g,则将 b b b减至该倍数所需步数为 b − ⌊ b g ⌋ ⋅ g = b % g b-\left\lfloor\dfrac{b}{g}\right\rfloor \cdot g=b\%g b−⌊gb⌋⋅g=b%g.
显然将 b b b加至 ≥ b \geq b ≥b的最小的 g g g的倍数所需步数为 g − b % g g-b\% g g−b%g.
代码
void solve() {
ll a, b; cin >> a >> b;
if (a == b) cout << "0 0" << endl;
else {
if (b > a) swap(a, b);
ll g = a - b;
cout << g << ' ' << min(b % g, g - b % g) << endl;
}
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1549A. Gregor and Cryptography
原题指路:https://codeforces.com/problemset/problem/1549/A
题意
给定一个素数 p p p,求两个整数 a , b s . t . 2 ≤ a < b ≤ p , p % a = p % b a,b\ s.t.\ 2\leq a<b\leq p,p\%a=p\%b a,b s.t. 2≤a<b≤p,p%a=p%b.
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据输入一个素数 p ( 5 ≤ p ≤ 1 e 9 ) p\ \ (5\leq p\leq 1\mathrm{e}9) p (5≤p≤1e9).
思路
因素数 p ≥ 5 p\geq 5 p≥5,则 p p p是奇数,进而 ( p − 1 ) (p-1) (p−1)是偶数.取 a = 2 , b = p − 1 a=2,b=p-1 a=2,b=p−1即可.
代码
void solve() {
int n; cin >> n;
cout << 2 << ' ' << n - 1 << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}