[Codeforces] number theory (R1600) Part.8
题单:https://codeforces.com/problemset/page/1?tags=number+theory%2C1201-1600
1242A. Tile Painting
原题指路:https://codeforces.com/problemset/problem/1242/A
题意
编号 1 ∼ n 1\sim n 1∼n的 n n n的格子排成一行.现对这些格子染色,定义一种染色方案是好的,如果对 ∀ i , j ( i ≠ j ) s . t . ∣ j − i ∣ \forall i,j\ \ (i\neq j)\ s.t.\ |j-i| ∀i,j (i=j) s.t. ∣j−i∣是 n n n的一个 > 1 >1 >1的约数,则它们颜色相同.给定 n ( 1 ≤ n ≤ 1 e 12 ) n\ \ (1\leq n\leq 1\mathrm{e}12) n (1≤n≤1e12),问至多能用多少种颜色染色,使得染色方案是好的.
思路
①若 n = p k ( p ∈ p r i m e s ) n=p^k\ \ (p\in primes) n=pk (p∈primes),因 n n n模 p p p有 p p p种余数,故 a n s = p ans=p ans=p.
②若 n = p q ( p , q > 1 ) n=pq\ \ (p,q>1) n=pq (p,q>1)且 gcd ( p , q ) = 1 \gcd(p,q)=1 gcd(p,q)=1,则 a n s = 1 ans=1 ans=1.
[证] 对 ∀ i , j ( i ≠ j ) \forall i,j\ \ (i\neq j) ∀i,j (i=j),由CRT: ∃ x ∈ [ 1 , n ] s . t . x ≡ i ( m o d p ) , x ≡ j ( m o d p ) \exists x\in[1,n]\ s.t.\ x\equiv i\ \ (\mathrm{mod}\ p),x\equiv j\ \ (\mathrm{mod}\ p) ∃x∈[1,n] s.t. x≡i (mod p),x≡j (mod p),
则下标 i , j i,j i,j与下标 x x x颜色相同,进而所有格子颜色相同.
代码
void solve() {
ll n; cin >> n;
for (int d = 2; (ll)d * d <= n; d++) {
if (n % d == 0) {
while (n % d == 0) n /= d;
if (n > 1) {
cout << 1;
return;
}
else {
cout << d;
return;
}
}
}
cout << n;
}
int main() {
solve();
}
1263C. Everyone is a Winner!
原题指路:https://codeforces.com/problemset/problem/1263/C
题意
有 t ( 1 ≤ t ≤ 10 ) t\ \ (1\leq t\leq 10) t (1≤t≤10)组测试数据.每组测试数据输入一个整数 n ( 1 ≤ n ≤ 1 e 9 ) n\ \ (1\leq n\leq 1\mathrm{e}9) n (1≤n≤1e9).对所有正整数 k k k,问 ⌊ n k ⌋ \left\lfloor\dfrac{n}{k}\right\rfloor ⌊kn⌋有多少种不同的取值,第一行输出不同取值的个数,第二行升序输出所有取值.
思路
所有 0 ≤ x < ⌊ n ⌋ 0\leq x<\left\lfloor\sqrt{n}\right\rfloor 0≤x<⌊n⌋都是解.
[证] 方程 ⌊ n k ⌋ = x \left\lfloor\dfrac{n}{k}\right\rfloor=x ⌊kn⌋=x等价于 x ≤ n k < x + 1 x\leq\dfrac{n}{k}<x+1 x≤kn<x+1,解得 k ∈ ( n x + 1 , n x ] k\in\left(\dfrac{n}{x+1},\dfrac{n}{x}\right] k∈(x+1n,xn],区间长度为 n x 2 + x \dfrac{n}{x^2+x} x2+xn.
注意到 x < ⌊ n ⌋ x<\left\lfloor\sqrt{n}\right\rfloor x<⌊n⌋时, n x 2 + x > 1 \dfrac{n}{x^2+x}>1 x2+xn>1,则区间内至少存在一个整数 k = ⌊ n x ⌋ k=\left\lfloor\dfrac{n}{x}\right\rfloor k=⌊xn⌋,故所有 x ∈ [ 0 , ⌊ n ⌋ ) x\in\left[0,\left\lfloor\sqrt{n}\right\rfloor\right) x∈[0,⌊n⌋)都是解.
整除分块求所有解即可.
代码
void solve() {
int n; cin >> n;
vi ans;
for (int l = 1, r, t; l <= n; l = r + 1) {
r = (t = n / l) ? min(n / t, n) : n;
ans.push_back(n / l);
}
ans.push_back(0);
reverse(all(ans)); // 注意翻转
cout << ans.size() << endl;
for (int i : ans) cout << i << ' ';
cout << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1266C. Diverse Matrix
原题指路:https://codeforces.com/problemset/problem/1266/C
题意
设 A A A是一个 r × c r\times c r×c的整型矩阵,其中元素未必不同.构造一个长度为 ( r + c ) (r+c) (r+c)的序列 b [ ] b[] b[],其中前 r r r个元素是 A A A每行的 gcd \gcd gcd,后 c c c个元素是 A A A每列的 gcd \gcd gcd.称序列 b [ ] b[] b[]是好的,如果其中的元素两两相异.定义好的序列的权值为其中元素的最大值.
给定两整数 r r r和 c ( 1 ≤ r , c ≤ 500 ) c\ \ (1\leq r,c\leq 500) c (1≤r,c≤500),构造一个 r × c r\times c r×c矩阵 A A A使得其产生的序列 b [ ] b[] b[]是好的,且其权值最小.无解输出 0 0 0.若有多组解,输出任一组解.
思路
① r = c = 1 r=c=1 r=c=1时无解.
② r = 1 r=1 r=1时,最优解为 A = [ 2 3 ⋯ c + 1 ] A=[2\ 3\ \cdots\ c+1] A=[2 3 ⋯ c+1],不取 1 ∼ c 1\sim c 1∼c是因为 1 1 1会重复.
③ c = 1 c=1 c=1时,最优解为 A = [ 2 3 ⋯ c + 1 ] T A=[2\ 3\ \cdots\ c+1]^T A=[2 3 ⋯ c+1]T.
④ r , c ≥ 2 r,c\geq 2 r,c≥2时,令 a i j = i ( j + r ) a_{ij}=i(j+r) aij=i(j+r),则 b i = gcd { i ( r + 1 ) , ⋯ , i ( r + c ) } = i ⋅ gcd { r + 1 , ⋯ , r + c } = i b_i=\gcd\{i(r+1),\cdots,i(r+c)\}=i\cdot \gcd\{r+1,\cdots,r+c\}=i bi=gcd{i(r+1),⋯,i(r+c)}=i⋅gcd{r+1,⋯,r+c}=i.
此时 b [ ] b[] b[]的权值为 ( r + c ) (r+c) (r+c),显然这是最小的.
代码
void solve() {
int r, c; cin >> r >> c;
if (r * c == 1) {
cout << 0;
return;
}
if (r == 1) {
for (int i = 2; i <= c + 1; i++) cout << i << ' ';
return;
}
else if (c == 1) {
for (int i = 2; i <= r + 1; i++) cout << i << endl;
return;
}
for (int i = 1; i <= r; i++)
for (int j = 1; j <= c; j++) cout << i * (j + r) << " \n"[j == c];
}
int main() {
solve();
}
1285C. Fadi and LCM
原题指路:https://codeforces.com/problemset/problem/1285/C
题意
给定一个整数 x ( 1 ≤ x ≤ 1 e 12 ) x\ \ (1\leq x\leq 1\mathrm{e}12) x (1≤x≤1e12),求两正整数 a , b s . t . l c m ( a , b ) = x a,b\ s.t.\ \mathrm{lcm}(a,b)=x a,b s.t. lcm(a,b)=x且 max { a , b } \max\{a,b\} max{a,b}最小.若有多组解,输出任一组.
思路I
将 x x x素因数分解后,枚举将素因子分配给 a a a和 b b b的所有方案,求 max { a , b } \max\{a,b\} max{a,b}的最小值.
代码I
vl factors;
void get(ll n) { // 对x素因数分解
for (ll d = 2; d * d <= n; d++) {
if (n % d == 0) {
ll cur = 1;
while (n % d == 0) n /= d, cur *= d;
factors.push_back(cur);
}
}
if (n > 1) factors.push_back(n);
}
void solve() {
ll x; cin >> x;
get(x);
ll ansa = INFF, ansb = INFF;
int n = factors.size();
for (int i = 0; i < (1 << n); i++) {
ll a = 1, b = 1;
for (int j = 0; j < n; j++) {
if (i >> j & 1) a *= factors[j];
else b *= factors[j];
}
if (max(a, b) < max(ansa, ansb)) ansa = a, ansb = b;
}
cout << ansa << ' ' << ansb;
}
int main() {
solve();
}
思路II
枚举 x x x的约数 d d d,检查是否有 l c m ( d , x d ) = x \mathrm{lcm}\left(d,\dfrac{x}{d}\right)=x lcm(d,dx)=x,更新 max { a , b } \max\{a,b\} max{a,b}的最小值.
代码II
void solve() {
ll x; cin >> x;
ll ans = 0;
for (ll d = 1; d * d <= x; d++)
if (x % d == 0 && lcm(d, x / d) == x) ans = d;
cout << ans << ' ' << x / ans;
}
int main() {
solve();
}
1294C. Product of Three Numbers
原题指路:https://codeforces.com/problemset/problem/1294/C
题意 ( 2 s ) (2\ \mathrm{s}) (2 s)
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据输入一个整数 n ( 2 ≤ n ≤ 1 e 9 ) n\ \ (2\leq n\leq 1\mathrm{e}9) n (2≤n≤1e9).求三个相异的正整数 a , b , c s . t . a , b , c ≥ 2 a,b,c\ s.t.\ a,b,c\geq 2 a,b,c s.t. a,b,c≥2且 n = a b c n=abc n=abc,若有解则第一行输出"YES",第二行输出任一组解;否则输出"NO".
思路
不妨设 a < b < c a<b<c a<b<c,下面最小化 a a a并最大化 c c c.设 a a a是 n n n的 > 1 >1 >1的最小约数, b b b是 n a \dfrac{n}{a} an的非 a a a的 > 1 >1 >1的最小约数,若 n a b ≠ a , b , 1 \dfrac{n}{ab}\neq a,b,1 abn=a,b,1,则找到一组解.
代码
void solve() {
int n; cin >> n;
uset<int> s;
for (int d = 2; (ll)d * d <= n; d++) { // 求n的>1的最小约数a
if (n % d == 0) {
n /= d;
s.insert(d);
break;
}
}
for (int d = 2; (ll)d * d <= n; d++) { // 求n/a的非a的>1的最小约数b
if (n % d == 0 && !s.count(d)) {
n /= d;
s.insert(d);
break;
}
}
if (s.size() < 2 || s.count(n) || n == 1) cout << "NO" << endl;
else {
cout << "YES" << endl;
s.insert(n);
for (auto i : s) cout << i << ' ';
cout << endl;
}
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1305C. Kuroni and Impossible Calculation
原题指路:https://codeforces.com/problemset/problem/1305/C
题意
给定一个长度为 n ( 2 ≤ n ≤ 2 e 5 ) n\ \ (2\leq n\leq 2\mathrm{e}5) n (2≤n≤2e5)的序列 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 ≤ 1000 ) m\ \ (1\leq m\leq 1000) m (1≤m≤1000),求 ∏ 1 ≤ i < j ≤ n ∣ a i − a j ∣ \displaystyle \prod_{1\leq i<j\leq n}|a_i-a_j| 1≤i<j≤n∏∣ai−aj∣,答案对 m m m取模.
思路
① n ≤ m n\leq m n≤m时,暴力求即可.
② n > m n>m n>m时,因模 m m m只有 m m m种余数,则至少存在两个数 a i , a j s . t . a i ≡ a j ( m o d m ) a_i,a_j\ s.t.\ a_i\equiv a_j\ \ (\mathrm{mod}\ m) ai,aj s.t. ai≡aj (mod m),故 a n s = 0 ans=0 ans=0.
代码
void solve() {
int n, m; cin >> n >> m;
vi a(n);
for (auto& ai : a) cin >> ai;
if (n > m) cout << 0;
else {
int ans = 1;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++) ans = (ll)abs(a[i] - a[j]) % m * ans % m;
cout << ans;
}
}
int main() {
solve();
}
1312C. Adding Powers
原题指路:https://codeforces.com/problemset/problem/1312/C
题意 ( 2 s 2\ \mathrm{s} 2 s)
序列 v 1 , ⋯ , v n v_1,\cdots,v_n v1,⋯,vn初始时都为零.现有操作:在第 i i i步(下标从 0 0 0开始)时,可选择跳过此步,也可选择一个下标 p o s ∈ [ 1 , n ] pos\in[1,n] pos∈[1,n],令 v p o s + = k i v_{pos}+=k^i vpos+=ki.给定一个序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an,问若干次操作后能否将序列 v [ ] v[] v[]变为序列 a [ ] a[] a[],若能则输出"YES";否则输出"NO".
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据第一行输入两个整数 n , k ( 1 ≤ n ≤ 30 , 2 ≤ k ≤ 100 ) n,k\ \ (1\leq n\leq 30,2\leq k\leq 100) n,k (1≤n≤30,2≤k≤100).第二行输入 n n n个整数 a 1 , ⋯ , a n ( 0 ≤ a i ≤ 1 e 16 ) a_1,\cdots,a_n\ \ (0\leq a_i\leq 1\mathrm{e}16) a1,⋯,an (0≤ai≤1e16).
思路
将每个 a i a_i ai表示成 k k k进制数,检查是否有相同的 k k k的幂次.
代码
const int MAXN = 35;
int n, k;
ll a[MAXN];
bool check() {
uset<int> s; // 记录用过的k的幂次
for (int i = 0; i < n; i++) {
ll x = a[i];
int d = 0; // k的幂次
while (x) {
if (x % k != 0 && x % k != 1) return false;
if (x % k == 1) {
if (s.count(d)) return false;
s.insert(d);
}
d++;
x /= k;
}
}
return true;
}
void solve() {
cin >> n >> k;
for (int i = 0; i < n; i++) cin >> a[i];
cout << (check() ? "YES" : "NO") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1332B. Composite Coloring
原题指路:https://codeforces.com/problemset/problem/1332/B
题意 ( 2 s ) (2\ \mathrm{s}) (2 s)
称一个正整数是好的,如果它能表示为两 > 1 >1 >1的正整数之积.称一个序列是好的,如果其所有元素都是好的.
给定一个长度为 n n n的好的序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an.现选定一个正整数 m ∈ [ 1 , m ] m\in[1,m] m∈[1,m],用编号 1 ∼ m 1\sim m 1∼m的 m m m种颜色给序列染色,使得每种颜色至少用一次,序列中每个元素被染有且只有一种颜色,任意两个相同颜色的元素的 gcd > 1 \gcd>1 gcd>1.注意相等的元素可染不同色.可以证明当所有 a i ≤ 1000 a_i\leq 1000 ai≤1000时有解.构造任一组染色方案,第一行输出所用颜色的种数,第二行输出一个染色方案.
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据第一行输入一个整数 n ( 1 ≤ n ≤ 1000 ) n\ \ (1\leq n\leq 1000) n (1≤n≤1000).第二行输入一个长度为 n n n的好的序列 a 1 , ⋯ , a n ( 4 ≤ a i ≤ 1000 ) a_1,\cdots,a_n\ \ (4\leq a_i\leq 1000) a1,⋯,an (4≤ai≤1000).数据保证所有测试数据的 n n n之和不超过 1 e 4 1\mathrm{e}4 1e4.
思路
对每个好的数 k k k,存在一个素数 p ≤ k s . t . p ∣ k p\leq \sqrt{k}\ s.t.\ p\mid k p≤k s.t. p∣k.因 1000 \sqrt{1000} 1000以内共 11 11 11个素数,则每个数与其素因子染相同颜色即可.
代码
const int MAXN = 1005;
vi res[MAXN]; // 含有最小素因子p的元素的下标
int ans[MAXN];
int get(int x) { // 求x的最小素因子
for (int i = 2; i * i <= x; i++)
if (x % i == 0) return i;
return x;
}
void solve() {
int n; cin >> n;
for (int i = 1; i < MAXN; i++) res[i].clear();
for (int i = 1; i <= n; i++) {
int a; cin >> a;
res[get(a)].push_back(i);
}
int color = 0;
for (int i = 1; i < MAXN; i++) {
if (res[i].size()) {
color++;
for (auto j : res[i]) ans[j] = color;
}
}
cout << color << endl;
for (int i = 1; i <= n; i++) cout << ans[i] << " \n"[i == n];
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1342C. Yet Another Counting Problem
原题指路:https://codeforces.com/problemset/problem/1342/C
题意 ( 3.5 s ) (3.5\ \mathrm{s}) (3.5 s)
给定两整数 a , b a,b a,b.现给定两整数 l , r l,r l,r,表示询问有多少个 x ∈ [ l , r ] s . t . ( x m o d a ) m o d b ≠ ( x m o d b ) m o d a x\in[l,r]\ s.t.\ (x\ \mathrm{mod}\ a)\ \mathrm{mod}\ b\neq (x\ \mathrm{mod}\ b)\ \mathrm{mod}\ a x∈[l,r] s.t. (x mod a) mod b=(x mod b) mod a.
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据第一行输入三个整数 a , b , q ( 1 ≤ a , b ≤ 200 , 1 ≤ q ≤ 500 ) a,b,q\ \ (1\leq a,b\leq 200,1\leq q\leq 500) a,b,q (1≤a,b≤200,1≤q≤500),其中 q q q表示询问书.接下来 q q q行每行输入两个整数 l , r ( 1 ≤ l ≤ r ≤ 1 e 18 ) l,r\ \ (1\leq l\leq r\leq 1\mathrm{e}18) l,r (1≤l≤r≤1e18),表示一个询问.
思路
注意到 [ ( x + a b ) m o d a ] m o d b = ( x m o d a ) m o d b [(x+ab)\ \mathrm{mod}\ a]\ \mathrm{mod}\ b=(x\ \mathrm{mod}\ a)\ \mathrm{mod}\ b [(x+ab) mod a] mod b=(x mod a) mod b,则 x x x有上述性质当且仅当 x m o d a b x\ \mathrm{mod}\ ab x mod ab有上述性质.
预处理出 l e n = a b len=ab len=ab内满足所需性质的数的个数的前缀和 p r e [ ] pre[] pre[],根据 ⌊ x l e n ⌋ \left\lfloor\dfrac{x}{len}\right\rfloor ⌊lenx⌋和 x % l e n x\% len x%len求 [ 1 , x ] [1,x] [1,x]中有多少个数满足所需性质.
代码
const int MAXN = 4e4 + 5;
int pre[MAXN]; // 满足所需性质的数的个数的前缀和
int len; // a*b
void init(int a,int b) {
len = a * b;
for (int i = 1; i <= len; i++)
pre[i] = pre[i - 1] + ((i % a) % b != (i % b) % a);
}
ll query(ll x) {
ll cnt = x / len, rest = x % len;
return cnt * pre[len] + pre[rest];
}
ll query(ll l, ll r) {
return query(r) - query(l - 1);
}
void solve() {
int a, b; cin >> a >> b;
init(a, b);
CaseT{
ll l, r; cin >> l >> r;
cout << query(l, r) << ' ';
}
cout << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1344A. Hilbert’s Hotel
原题指路:https://codeforces.com/problemset/problem/1344/A
题意
有无限个房间,其中编号 0 ∼ ( n − 1 ) 0\sim (n-1) 0∼(n−1)的 n n n个房间分别住着客人 a 0 , ⋯ , a n − 1 a_0,\cdots,a_{n-1} a0,⋯,an−1.现有操作:对每个整数 k ∈ [ 0 , k − 1 ] k\in[0,k-1] k∈[0,k−1],将 k k k号房间的客人移动到 ( k + a k m o d n ) (k+a_{k\ \mathrm{mod}\ n}) (k+ak mod n)号房间.问操作后 0 ∼ ( n − 1 ) 0\sim (n-1) 0∼(n−1)号房间是否有且只有一个客人.
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据第一行输入一个整数 n ( 1 ≤ n ≤ 2 e 5 ) n\ \ (1\leq n\leq 2\mathrm{e}5) n (1≤n≤2e5).第二行输入一个长度为 n n n的序列 a 0 ⋯ , a n − 1 ( − 1 e 9 ≤ a i ≤ 1 e 9 ) a_0\cdots,a_{n-1}\ \ (-1\mathrm{e}9\leq a_i\leq 1\mathrm{e}9) a0⋯,an−1 (−1e9≤ai≤1e9).数据保证所有测试数据的 n n n之和不超过 2 e 5 2\mathrm{e}5 2e5.
思路
0 ∼ ( n − 1 ) 0\sim (n-1) 0∼(n−1)号房间是否有且只有一个客人等价于没有两个客人在同一房间且没有空房间.
设操作后存在两个客人在同一房间,则 x + a x m o d n = y + a y m o d n x+a_{x\ \mathrm{mod}\ n}=y+a_{y\ \mathrm{mod}\ n} x+ax mod n=y+ay mod n至少有一整数解.
设 x = k 1 n + i , y = k 2 n + j x=k_1n+i,y=k_2n+j x=k1n+i,y=k2n+j,则原方程 ⇔ x − y = a y m o d n − a x m o d n ⇔ k 1 n + i − k 2 n − j = a j − a i \Leftrightarrow x-y=a_{y\ \mathrm{mod}\ n}-a_{x\ \mathrm{mod}\ n}\Leftrightarrow k_1n+i-k_2n-j=a_j-a_i ⇔x−y=ay mod n−ax mod n⇔k1n+i−k2n−j=aj−ai,
则 ( k 1 − k 2 ) n = a j − a i + j − i = ( a j + j ) − ( a i + i ) (k_1-k_2)n=a_j-a_i+j-i=(a_j+j)-(a_i+i) (k1−k2)n=aj−ai+j−i=(aj+j)−(ai+i).
设 b i = a i + i b_i=a_i+i bi=ai+i,则等价于求 ( k 1 − k 2 ) n = c j − c i (k_1-k_2)n=c_j-c_i (k1−k2)n=cj−ci的正整数解 c i , c j c_i,c_j ci,cj,显然这等价于 c i ≡ c j ( m o d n ) c_i\equiv c_j\ \ (\mathrm{mod}\ n) ci≡cj (mod n).
预处理出所有 ( i + a i ) m o d n (i+a_i)\ \mathrm{mod}\ n (i+ai) mod n,检查余数是否为 0 ∼ ( n − 1 ) 0\sim (n-1) 0∼(n−1)即可.
代码
void solve() {
int n; cin >> n;
vi a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
a[i] = ((i + a[i]) % n + n) % n;
}
sort(all(a));
bool ok = true;
for (int i = 0; i < n; i++) ok &= a[i] == i;
cout << (ok ? "YES" : "NO") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}