[Codeforces] number theory (R1600) Part.3

[Codeforces] number theory (R1600) Part.3

题单:https://codeforces.com/problemset/page/1?tags=number+theory%2C1201-1600

346A. Alice and Bob

原题指路:https://codeforces.com/problemset/problem/346/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

Alice和Bob两人玩游戏,Alice先手.初始时给定一个整数集合 S S S.每轮玩家选两个相异的整数 x , y ∈ S x,y\in S x,yS,使得 ∣ x − y ∣ ∉ S |x-y|\not\in S xyS,并将 ∣ x − y ∣ |x-y| xy加入 S S S中,不能操作者负.问最后谁赢.

第一行输入一个整数 n    ( 2 ≤ n ≤ 100 ) n\ \ (2\leq n\leq 100) n  (2n100).第二行输入 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  (1ai1e9).

思路

类似于闭包,无论中间过程,最后得到的集合都相同.设 g = gcd ⁡ 1 ≤ i ≤ n a i \displaystyle g=\gcd_{1\leq i\leq n}a_i g=1ingcdai,则最终集合为 { d , 2 d , 3 d , ⋯   , max ⁡ { x i } } \{d,2d,3d,\cdots,\max\{x_i\}\} {d,2d,3d,,max{xi}},故轮数为 max ⁡ { x i } d \dfrac{\max\{x_i\}}{d} dmax{xi},判断其奇偶性即可.

代码

void solve() {
	int n; cin >> n;
	valarray<int> a(n);
	int g = 0;  // gcd
	for (auto& ai : a) {
		cin >> ai;
		g = gcd(g, ai);
	}

	int ans = a.max() / g - n;
	cout << (ans & 1 ? "Alice" : "Bob");
}

int main() {
	solve();
}


353C. Find Maximum

原题指路:https://codeforces.com/problemset/problem/353/C

题意

给定一个长度为 n n n的序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an.定义函数 f ( x ) = ∑ i = 0 n − 1 a i ⋅ b i t ( i ) \displaystyle f(x)=\sum_{i=0}^{n-1} a_i\cdot bit(i) f(x)=i=0n1aibit(i),它以 [ 0 , 2 n − 1 ] [0,2^n-1] [0,2n1]中的一个整数为参数 x x x,其中 b i t ( i ) = 1 bit(i)=1 bit(i)=1当且仅当参数 x x x的二进制表示第 i i i位为 1 1 1;否则 b i t ( i ) = 0 bit(i)=0 bit(i)=0.如 n = 4 , x = 11 = 2 0 + 2 1 + 2 3 n=4,x=11=2^0+2^1+2^3 n=4,x=11=20+21+23时, f ( x ) = a 0 + a 1 + a 3 f(x)=a_0+a_1+a_3 f(x)=a0+a1+a3.给定一个整数 m m m,求 f ( x ) f(x) f(x) x ∈ [ 0 , m ] x\in[0,m] x[0,m]上的最大值.

第一行输入一个整数 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5).第二行输入 n n n个整数 a 1 , ⋯   , a n    ( 0 ≤ a i ≤ 1 e 4 ) a_1,\cdots,a_n\ \ (0\leq a_i\leq 1\mathrm{e}4) a1,,an  (0ai1e4).第三行输入一个长度为 n n n 0 − 1 0-1 01串,表示整数 m m m的二进制表示.

思路I

①若 m m m的MSB为 0 0 0,则 ∀ x ∈ [ 0 , m ] \forall x\in[0,m] x[0,m]的二进制表示的第 ( n − 1 ) (n-1) (n1)位为 0 0 0,则 a n − 1 a_{n-1} an1不会出现在 f ( x ) f(x) f(x)中.

②若 m m m的MSB为 1 1 1,则对某些 x x x, a n − 1 a_{n-1} an1会出现在 f ( x ) f(x) f(x)中.考察不包含 a n − 1 a_{n-1} an1 f ( x ) f(x) f(x),显然此时 x ∈ [ 0 , 2 n − 1 − 1 ] x\in[0,2^{n-1}-1] x[0,2n11].

​ 故 x = 2 n − 1 − 1 x=2^{n-1}-1 x=2n11 f ( x ) f(x) f(x)取得最大值.

从高位到地位枚举 m m m的二进制表示的数位,数位为 1 1 1时更新答案即可,过程用前缀和、后缀和加速.

代码I

const int MAXN = 1e5 + 5;
int n;
int a[MAXN];
int pre[MAXN];  // a[]的前缀和
string s;

void solve() {
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
		pre[i + 1] = pre[i] + a[i];
	}
	cin >> s;

	int ans = 0;
	for (int i = n - 1, suf = 0; i >= 0; i--)  // suf为a[]的后缀和
		if (s[i] == '1') ans = max({ ans,pre[i] + suf,suf += a[i] });
	cout << ans;
}

int main() {
	solve();
}


371B. Fox Dividing Cheese

原题指路:https://codeforces.com/problemset/problem/371/B

题意

给定两整数 a , b a,b a,b.现有如下三种操作,选定一个数 x x x:①若 2 ∣ x 2\mid x 2x,令 x − = x 2 x-=\dfrac{x}{2} x=2x;②若 3 ∣ x 3\mid x 3x,令 x − = 2 3 x x-=\dfrac{2}{3}x x=32x;③若 5 ∣ x 5\mid x 5x,令 x − = 4 5 x x-=\dfrac{4}{5}x x=54x.若经若干次操作后能使得 a = b a=b a=b,输出最小操作次数;否则输出 − 1 -1 1.

思路

显然操作①等价于 x / = 2 x/=2 x/=2,操作②等价于 x / = 3 x/=3 x/=3,操作③等价于 x / = 5 x/=5 x/=5.

a = x ⋅ 2 α 1 ⋅ 3 α 2 ⋅ 5 α 3 , b = y ⋅ 2 β 1 ⋅ 3 β 2 ⋅ 5 β 3 a=x\cdot 2^{\alpha_1}\cdot 3^{\alpha_2}\cdot 5^{\alpha_3},b=y\cdot 2^{\beta_1}\cdot 3^{\beta_2}\cdot 5^{\beta_3} a=x2α13α25α3,b=y2β13β25β3.

①若 x ≠ y x\neq y x=y,显然无解.

②若 x = y x=y x=y,则 a n s = ∣ α 1 − β 1 ∣ + ∣ α 2 − β 2 ∣ + ∣ α 3 − β 3 ∣ ans=|\alpha_1-\beta_1|+|\alpha_2-\beta_2|+|\alpha_3-\beta_3| ans=α1β1+α2β2+α3β3.

代码

vi get(int n) {
	vi res(4, 0);  // 素因子2的次数、3的次数、5的次数、余下的因子之积
	while (n % 2 == 0) {
		n /= 2;
		res[0]++;
	}
	while (n % 3 == 0) {
		n /= 3;
		res[1]++;
	}
	while (n % 5 == 0) {
		n /= 5;
		res[2]++;
	}
	res[3] = n;
	return res;
}

void solve() {
	int a, b; cin >> a >> b;

	auto res1 = get(a), res2 = get(b);
	if (res1[3] != res2[3]) cout << -1;
	else cout << abs(res1[0] - res2[0]) + abs(res1[1] - res2[1]) + abs(res1[2] - res2[2]);
}

int main() {
	solve();
}


375A. Divisible by Seven

原题指路:https://codeforces.com/problemset/problem/375/A

题意

给定一个至少包含包含数码 1 , 6 , 8 , 9 1,6,8,9 1,6,8,9的整数 a a a,重排其数码使得其能被 7 7 7整除,输出重排后的数字(无前导零),无解输出 0 0 0.

思路

考察 1 , 6 , 8 , 9 1,6,8,9 1,6,8,9是否能拼出模 7 7 7后余数为 0 ∼ 6 0\sim 6 06的所有数.枚举知: 1869 % 7 = 0 , 8961 % 7 = 1 , 1689 % 7 = 2 , 6198 % 7 = 3 , 1698 % 7 = 4 , 9861 % 7 = 5 , 1896 % 7 = 6 1869\% 7=0,8961\% 7=1,1689\% 7=2,6198\% 7=3,1698\% 7=4,9861\% 7=5,1896\% 7=6 1869%7=0,8961%7=1,1689%7=2,6198%7=3,1698%7=4,9861%7=5,1896%7=6.故前面的数码任意排,后面补上对应余数的 1 , 6 , 8 , 9 1,6,8,9 1,6,8,9的排列即可.

因不输出前导零,将所有 0 0 0放在最后输出即可,显然这不影响余数.

代码

const int MAXN = 10;
const int last[] = { 1869,8961,1689,6198,1698,9861,1896,1869 };
int cnt[MAXN];  // 每个数码出现的次数

void solve() {
	string s; cin >> s;
	for (auto ch : s) cnt[ch & 15]++;

	cnt[1]--, cnt[6]--, cnt[8]--, cnt[9]--;

	int r = 0;  // 余数
	for (int i = 1; i < 10; i++) {
		while (cnt[i]--) {
			r = (r * 10 + i) % 7;
			cout << i;
		}
	}
	cout << last[7 - r * 10000 % 7];
	while (cnt[0]--) cout << 0;
}

int main() {
	solve();
}


414A. Mashmokh and Numbers

原题指路:https://codeforces.com/problemset/problem/414/A

题意

给定一个长度为 n n n的序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an.现有操作:若当前序列元素个数 ≥ 2 \geq 2 2,取序列的前两个元素 x , y x,y x,y,将它们删去,同时获得 gcd ⁡ ( x , y ) \gcd(x,y) gcd(x,y)的分数.构造一个元素相异的序列$a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}9)\ s.t.\ 操作后总得分为 操作后总得分为 操作后总得分为k . 无解输出 .无解输出 .无解输出-1$.

第一行输入两个整数 n , k    ( 1 ≤ n ≤ 1 e 5 , 0 ≤ k ≤ 1 e 8 ) n,k\ \ (1\leq n\leq 1\mathrm{e}5,0\leq k\leq 1\mathrm{e}8) n,k  (1n1e5,0k1e8).

思路

显然每次操作至少获得 1 1 1分,则 k < ⌊ n 2 ⌋ k<\left\lfloor\dfrac{n}{2}\right\rfloor k<2n时无解.

k ≥ n 2 k\geq \dfrac{n}{2} k2n时,考察 x = k − ⌊ n − 2 2 ⌋ x=k-\left\lfloor\dfrac{n-2}{2}\right\rfloor x=k2n2,取 a 1 = x , a 2 = 2 x a_1=x,a_2=2x a1=x,a2=2x,其余元素取一个连续的升序序列即可.

注意特判 n = 1 n=1 n=1的情况,此时有解当且仅当 k = 0 k=0 k=0.

代码

void solve() {
	int n, k; cin >> n >> k;
	
	if (n == 1) cout << (k ? -1 : 1);
	else if (k < n / 2) cout << -1;
	else {
		int x = k - (n - 2) / 2;
		cout << x << ' ' << 2 * x << ' ';
		for (int i = 2 * x + 1; i <= 2 * x  + n - 2; i++) cout << i << ' ';
	}
}

int main() {
	solve();
}


414B. Mashmokh and ACM

原题指路:https://codeforces.com/problemset/problem/414/B

题意

称一个整数序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an是好的,如果 a i ∣ a i + 1    ( 1 ≤ i ≤ n − 1 ) a_i\mid a_{i+1}\ \ (1\leq i\leq n-1) aiai+1  (1in1).给定整数 n , k    ( 1 ≤ n , k ≤ 2000 ) n,k\ \ (1\leq n,k\leq 2000) n,k  (1n,k2000),求长度为 k k k的、元素范围为 [ 1 , n ] [1,n] [1,n]的好的整数序列的个数,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

思路

d p [ i ] [ j ] dp[i][j] dp[i][j]表示长度为 i i i的、以 j j j结尾的好的序列的个数.枚举 j j j的约数 d d d,状态转移方程 d p [ i ] [ j ] = ∑ d ∣ x d p [ i − 1 ] [ d ] \displaystyle dp[i][j]=\sum_{d\mid x}dp[i-1][d] dp[i][j]=dxdp[i1][d].初始条件可取 d p [ 0 ] [ 1 ] = 1 dp[0][1]=1 dp[0][1]=1.

暴力转移时间复杂度 O ( k n n ) O(kn\sqrt{n}) O(knn ),会TLE.考虑优化,先预处理出 2000 2000 2000内所有数的约数,总时间复杂度 O ( k n log ⁡ n ) O(kn\log n) O(knlogn).

代码

const int MAXN = 2005;
const int MOD = 1e9 + 7;
vi divisors[MAXN];  // 存每个数的约数
int dp[MAXN][MAXN];  // dp[i][j]表示长度为i的、以j结尾的好的序列的个数

void init() {
	for (int i = 1; i < MAXN; i++)
		for (int j = i; j < MAXN; j += i) divisors[j].push_back(i);
}

void solve() {
	init();

	int n, k; cin >> n >> k;
	
	dp[0][1] = 1;
	for (int i = 1; i <= k; i++) {
		for (int j = 1; j <= n; j++) {
			for (auto d : divisors[j])
				dp[i][j] = ((ll)dp[i][j] + dp[i - 1][d]) % MOD;
		}
	}

	int ans = 0;
	for (int i = 1; i <= n; i++) ans = ((ll)ans + dp[k][i]) % MOD;
	cout << ans;
}

int main() {
	solve();
}


460B. Little Dima and Equation

原题指路:https://codeforces.com/problemset/problem/460/B

题意

给定系数 a , b , c    ( 1 ≤ a ≤ 5 , 1 ≤ b ≤ 1 e 4 , − 1 e 4 ≤ c ≤ 1 e 4 ) a,b,c\ \ (1\leq a\leq 5,1\leq b\leq 1\mathrm{e}4,-1\mathrm{e}4\leq c\leq 1\mathrm{e}4) a,b,c  (1a5,1b1e4,1e4c1e4),求方程 x = b ⋅ s ( x ) a + c x=b\cdot s(x)^a+c x=bs(x)a+c x ∈ ( 0 , 1 e 9 ) x\in(0,1\mathrm{e}9) x(0,1e9)中的所有整数解,其中 s ( x ) s(x) s(x)表示 x x x的十进制表示的数位之和.第一行输出解的个数,第二行升序输出所有解.

思路

注意到对 ∀ x ∈ ( 0 , 1 e 9 ) , s ( x ) ∈ [ 1 , 81 ] \forall x\in(0,1\mathrm{e}9),s(x)\in[1,81] x(0,1e9),s(x)[1,81],故可枚举 s s s,求出对应的 x x x后,判断是否 s ( x ) = s s(x)=s s(x)=s x < 1 e 9 x<1\mathrm{e}9 x<1e9即可.

代码

int get_sum(int x) {
  int res = 0;
  while (x) {
    res += x % 10;
    x /= 10;
  }
  return res;
}

ll qpow(int a, int k) {
  ll res = 1;
  while (k) {
    if (k & 1) res = res * a;
    k >>= 1;
    a = a * a;
  }
  return res;
}

void solve() {
  int a, b, c; cin >> a >> b >> c;

  vi ans;
  for (int s = 1; s <= 81; s++) {
    ll x = qpow(s, a) * b + c;
    if (get_sum(x) == s && x < 1e9) ans.push_back(x);
  }

  cout << ans.size() << endl;
  for (auto i : ans) cout << i << ' ';
}

int main() {
  solve();
}


495B. Modular Equations

原题指路:https://codeforces.com/problemset/problem/495/B

题意

给定整数 a , b    ( 0 ≤ a , b ≤ 1 e 9 ) a,b\ \ (0\leq a,b\leq 1\mathrm{e}9) a,b  (0a,b1e9),求关于 x x x的方程 a   m o d   x = b a\ \mathrm{mod}\ x=b a mod x=b的解数,无解输出 0 0 0,有无穷多组解输出"infinity".

思路

a < b a<b a<b时,显然无解.

a = b a=b a=b时, ∀ x > a \forall x>a x>a都是方程的解.

a > b a>b a>b时,显然 x ∣ ( a − b ) x\mid (a-b) x(ab),且 x > b x>b x>b.故方程的解数即 ( a − b ) (a-b) (ab) > b >b >b的约数个数.

代码

void solve() {
  int a, b; cin >> a >> b;

  if (a < b) cout << 0;
  else if (a == b) cout << "infinity";
  else {
    int c = a - b;
    int ans = 0;
    for (int i = 1; i <= c / i; i++) 
      if (c % i == 0) ans += (i > b) + (i != c / i && c / i > b);
    cout << ans;
  }
}

int main() {
  solve();
}


515B. Drazil and His Happy Friends

原题指路:https://codeforces.com/problemset/problem/515/B

题意 ( 2   s 2\ \mathrm{s} 2 s)

n n n个男生和 m m m个女生,分别编号 0 ∼ ( n − 1 ) 0\sim (n-1) 0(n1) 0 ∼ ( m − 1 ) 0\sim (m-1) 0(m1).初始时他们之中有些人开心,有些人不开心.现第 i i i天会邀请编号 ( i   m o d   n ) (i\ \mathrm{mod}\ n) (i mod n)的男生和编号 ( i   m o d   m ) (i\ \mathrm{mod}\ m) (i mod m)的女生吃饭,若两人中有一人开心,则两人都会永久地开心.问最后能否使得所有人开心,若能则输出"Yes";否则输出"No".

第一行输入两个整数 n , m    ( 1 ≤ n , m ≤ 100 ) n,m\ \ (1\leq n,m\leq 100) n,m  (1n,m100).第二行先输入一个整数 b    ( 0 ≤ b ≤ n ) b\ \ (0\leq b\leq n) b  (0bn).接下来输入 b b b个整数 x 1 , ⋯   , x b    ( 0 ≤ x i < n ) x_1,\cdots,x_b\ \ (0\leq x_i<n) x1,,xb  (0xi<n),表示初始时开心的男生.第三行先输入一个整数 g    ( 0 ≤ g ≤ m ) g\ \ (0\leq g\leq m) g  (0gm).接下来输入 g g g个整数 y 1 , ⋯   , y b    ( 0 ≤ y i < m ) y_1,\cdots,y_b\ \ (0\leq y_i<m) y1,,yb  (0yi<m),表示初始时开心的女生.

思路

显然至多 n m nm nm天会出现循环,若 n m nm nm天后还有人不开心,则答案为No.可模拟前 n m nm nm天的情况,时间复杂度 O ( n m ) O(nm) O(nm).

事实上本题有 O ( n + m ) O(n+m) O(n+m)的解法.设 g = gcd ⁡ ( n , m ) g=\gcd(n,m) g=gcd(n,m).若 i i i号人开心,则编号为 x ≡ i    ( m o d   g ) x\equiv i\ \ (\mathrm{mod}\ g) xi  (mod g)的人都会变开心,则只需考察编号 m o d   g \mathrm{mod}\ g mod g的每个余数中是否至少有一个人开心即可.

代码

const int MAXN = 105;
bool happy[MAXN];

void solve() {
	int n, m; cin >> n >> m;
	int g = gcd(n, m);

	int xn; cin >> xn;
	while (xn--) {
		int x; cin >> x;
		happy[x % g] = true;
	}
	int yn; cin >> yn;
	while (yn--) {
		int y; cin >> y;
		happy[y % g] = true;
	}

	for (int i = 0; i < g; i++) {
		if (!happy[i]) {
			cout << "No";
			return;
		}
	}
	cout << "Yes";
}

int main() {
	solve();
}


519C. A and B and Team Training

原题指路:https://codeforces.com/problemset/problem/519/C

题意

一支队伍有如下两种组成方式:① 1 1 1个A类人和 2 2 2个B类人;② 2 2 2个A类人和 1 1 1个B类人.现有 n n n个A类人和 m    ( 0 ≤ n , m ≤ 5 e 5 ) m\ \ (0\leq n,m\leq 5\mathrm{e}5) m  (0n,m5e5)个B类人,求最多能组成多少支队伍.

思路

设组成①类队 i    ( 0 ≤ i ≤ n ) i\ \ (0\leq i\leq n) i  (0in)支,则剩余 ( n − i ) (n-i) (ni)个A类人和 ( m − 2 i ) (m-2i) (m2i)个B类人,他们能组成②类队 min ⁡ { n − i 2 , m − 2 i } \min\left\{\dfrac{n-i}{2},m-2i\right\} min{2ni,m2i}.枚举每个 i i i,更新答案即可.

代码

void solve() {
  int n, m; cin >> n >> m;

  int ans = 0;
  for (int i = 0; i <= n; i++) {  // 枚举①类队队伍数
    int res = i;
    if (m - 2 * i >= 0) {
      res += min((n - i) / 2, m - 2 * i);
      ans = max(ans, res);
    }
  }
  cout << ans;
}

int main() {
  solve();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值