[Codeforces] number theory (R1600) Part.2

[Codeforces] number theory (R1600) Part.2

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

235A. LCM Challenge

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

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

给定一个整数 n    ( 1 ≤ n ≤ 1 e 6 ) n\ \ (1\leq n\leq 1\mathrm{e}6) n  (1n1e6),求三个 ≤ n \leq n n的正整数使得它们的 l c m \mathrm{lcm} lcm最大,输出 l c m \mathrm{lcm} lcm的最大值.

思路

显然应取尽量大的互素的数.

(1)若 n n n为奇数,显然 a n s = n ( n − 1 ) ( n − 2 ) ans=n(n-1)(n-2) ans=n(n1)(n2).

(2)若 n n n是偶数,显然应避开同时选 n n n n − 2 n-2 n2的情况.

​ ①若 3 ∣ n 3\mid n 3n,则 n , ( n − 1 ) , ( n − 3 ) n,(n-1),(n-3) n,(n1),(n3) gcd ⁡ ( n , n − 3 ) ≥ 3 \gcd(n,n-3)\geq 3 gcd(n,n3)3,应取 a n s = ( n − 1 ) ( n − 2 ) ( n − 3 ) ans=(n-1)(n-2)(n-3) ans=(n1)(n2)(n3).

​ ②若 3 ∤ n 3\not\mid n 3n,则 a n s = n ( n − 1 ) ( n − 3 ) ans=n(n-1)(n-3) ans=n(n1)(n3).

注意特判 n ≤ 3 n\leq 3 n3的情况.

代码

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

  if (n == 1) cout << 1;
  else if (n == 2) cout << 2;
  else if (n == 3) cout << 6;
  else if (n & 1) cout << (ll)n * (n - 1) * (n - 2);
  else if (n % 3 == 0) cout << (ll)(n - 1) * (n - 2) * (n - 3);
  else cout << (ll)n * (n - 1) * (n - 3);
}

int main() {
	solve();
}


236B. Easy Number Challenge

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

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

对正整数 n n n,定义 d ( n ) d(n) d(n) n n n的约数的个数.给定 a , b , c    ( 1 ≤ a , b , c ≤ 100 ) a,b,c\ \ (1\leq a,b,c\leq 100) a,b,c  (1a,b,c100),求 ∑ i = 1 a ∑ j = 1 b ∑ k = 1 c d ( i j k ) \displaystyle\sum_{i=1}^a \sum_{j=1}^b \sum_{k=1}^c d(ijk) i=1aj=1bk=1cd(ijk),答案对 2 30 2^{30} 230取模.

思路

预处理出 i j k ≤ 1 e 6 ijk\leq 1\mathrm{e}6 ijk1e6内的 d ( i j k ) d(ijk) d(ijk),直接统计答案即可.

代码

const int MAXN = 1e6 + 5;
const int MOD = 1 << 30;
int primes[MAXN], cnt;
bool state[MAXN];
int nums[MAXN];  // 数的素因子个数
int d[MAXN];  // 约数个数

void init() {
  d[1] = 1;
  for (int i = 2; i < MAXN; i++) {
    if(!state[i]) {
      state[i] = true;
      primes[cnt++] = i;
      nums[i] = 1;
      d[i] = 2;  // 素数
    }

    for (int j = 0; (ll)primes[j] * i < MAXN; j++) {
      state[primes[j] * i] = true;
      if (i % primes[j] == 0) {
        nums[primes[j] * i] = nums[i] + 1;
        d[primes[j] * i] = d[i] / nums[primes[j] * i] * (nums[primes[j] * i] + 1);
        break;
      }
      else {
        nums[primes[j] * i] = 1;
        d[primes[j] * i] = d[i] * 2;
      }
    }
  }
}

void solve() {
  init();

  int a, b, c; cin >> a >> b >> c;

  ll ans = 0;
  for (int i = 1; i <= a; i++) {
    for (int j = 1; j <= b; j++) {
      for (int k = 1; k <= c; k++)
        ans += d[i * j * k];
    }
  }
  cout << ans;
}

int main() {
	solve();
}


237C. Primes on Interval

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

题意

给定三个整数 a , b , k    ( 1 ≤ a , b , k ≤ 1 e 6 , a ≤ b ) a,b,k\ \ (1\leq a,b,k\leq 1\mathrm{e}6,a\leq b) a,b,k  (1a,b,k1e6,ab).求一个最小的整数$l\ \ (1\leq l\leq b-a+1)\ s.t.\ 对 对 \forall x\in[a,b-l+1] , 在 ,在 ,x,x+1,\cdots,x+l-1 中至少有 中至少有 中至少有k 个素数 , 若无解输出 个素数,若无解输出 个素数,若无解输出-1$.

思路

预处理出 1 e 6 1\mathrm{e}6 1e6内的素数,并预处理出素数个数的前缀和 p r e [ ] pre[] pre[].二分 l l l的值即可.

代码

const int MAXN = 1e6 + 5;
int a, b, k; 
bool not_prime[MAXN];
int pre[MAXN];  // 素数的个数

void init() {
  not_prime[1] = true;
  for (int i = 2; i < MAXN; i++) {
    if (!not_prime[i]) 
      for (int j = 2 * i; j < MAXN; j += i) not_prime[j] = true;
  }

  for (int i = 1; i < MAXN; i++) pre[i] = pre[i - 1] + !not_prime[i];
}

bool check(int mid) {
  for (int i = a; i + mid - 1 <= b; i++)
    if (pre[i + mid - 1] - pre[i - 1] < k) return false;
  return true;
}

void solve() {
  init();

	cin >> a >> b >> k;

  int l = 1, r = b - a + 2;  // 注意r的取值范围为l的最大值+1
  while (l < r) {
    int mid = l + r >> 1;
    if (check(mid)) r = mid;
    else l = mid + 1;
  }
  cout << (l == b - a + 2 ? -1 : l);
}

int main() {
	solve();
}


248B. Chilly Willy

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

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

求一个最小的长度为 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5)的整数使得它能被 2 , 3 , 5 , 7 2,3,5,7 2,3,5,7整除,无解输出 − 1 -1 1.

思路

显然 n ≤ 2 n\leq 2 n2时无解.

n ≥ 3 n\geq 3 n3的情况,解是 210 210 210的倍数.

n = 3 n=3 n=3时, a n s = 210 ans=210 ans=210.

n ≥ 3 n\geq 3 n3时,考虑构造一个整数 1 0 ⋯ 0 ⏟ ( n − 4 ) 个 ? ? ? ‾ \overline{1\underbrace{0\cdots 0}_{(n-4)个}???} 1(n4) 00???,其中最后三位用于使得该数模 210 210 210 0 0 0,大数取模即可.

代码

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

  if (n <= 2) cout << -1;
  else if (n == 3) cout << 210;
  else {
    int rest = 10;  // ans % 210
    for (int i = 3; i <= n; i++) rest = (rest * 10) % 210;
    rest = 210 - rest;  // 加到下一个210的倍数所需的步数

    cout << 1;
    for (int i = 4; i < n; i++) cout << 0;  // 中间的(n-4)位
    printf("%03d", rest);
  }
}

int main() {
	solve();
}


264B. Good Sequences

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

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

给定一个长度为 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5)的序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an.称 a [ ] a[] a[]的一个子列 x 1 , ⋯   , x k x_1,\cdots,x_k x1,,xk是好的,如果它满足如下两条件:①严格递增,即 x i < x i + 1    ( 1 ≤ i ≤ k − 1 ) x_i<x_{i+1}\ \ (1\leq i\leq k-1) xi<xi+1  (1ik1);②任意两相邻元素不互素,即 gcd ⁡ ( x i , x i + 1 ) > 1    ( 1 ≤ i ≤ k − 1 ) \gcd(x_i,x_{i+1})>1\ \ (1\leq i\leq k-1) gcd(xi,xi+1)>1  (1ik1).求最长的好的子列的长度.

思路

d p [ a ] dp[a] dp[a]表示以元素 a a a结尾的满足条件的LIS的长度,最终答案 a n s = max ⁡ 1 ≤ i ≤ 1 e 5 d p [ i ] \displaystyle ans=\max_{1\leq i\leq 1\mathrm{e}5} dp[i] ans=1i1e5maxdp[i].

对序列的每个元素 x x x,设它能接到末尾的最长序列长度为 r e s res res.枚举 x x x不超过 x \sqrt{x} x 的约数 j j j,则 x x x能接到末尾的状态是 d p [ j ] dp[j] dp[j] d p [ x / j ] dp[x/j] dp[x/j],注意 1 1 1是所有数的约数,而只有 j > 1 j>1 j>1 d p [ j ] dp[j] dp[j]才是合法状态. r e s = max ⁡ d ∣ x d p [ d ] \displaystyle res=\max_{d\mid x}dp[d] res=dxmaxdp[d],将 x x x接到序列末尾,即 r e s + + res++ res++后,对 x x x的约数 d d d,用 r e s res res更新 d p [ d ] dp[d] dp[d]即可.

代码

const int MAXN = 1e5 + 5;
int dp[MAXN];  // dp[a]以元素a结尾的满足条件的LIS的长度
int ans;

void solve() {
  int n; cin >> n;
  for (int i = 0; i < n; i++) {
    int x; cin >> x;

    int res = 0;
    for (int j = 1; (ll)j * j <= x; j++) {
      if (x % j == 0) {
        if (j > 1) res = max(res, dp[j]);  // 注意j>1时才可转移
        res = max(res, dp[x / j]);
      }
    }

    res++;
    for (int j = 1; (ll)j * j <= x; j++) 
      if (x % j == 0) dp[j] = dp[x / j] = res;
    ans = max(ans, res);
  }
  cout << ans;
}

int main() {
	solve();
}


271B. Prime Matrix

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

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

称一个矩阵是好的,如果至少存在一行或一列使得其中的元素都是素数.给定一个 n × m    ( 1 ≤ n , m ≤ 500 ) n\times m\ \ (1\leq n,m\leq 500) n×m  (1n,m500)的整数矩阵,元素范围为 [ 1 , 1 e 5 ] [1,1\mathrm{e}5] [1,1e5].现有操作:选择一个矩阵元素,将其 + 1 +1 +1 − 1 -1 1.问将矩阵变为好的矩阵的最小操作次数.

思路

预处理出 1 e 5 1\mathrm{e}5 1e5内的素数,求出一个新的矩阵,其中新的矩阵的元素是原矩阵中对应元素与不小于它的素数的距离,求新矩阵每行和每列的和,取 min ⁡ \min min即可.

代码

const int MAXN = 1e5 + 5;
int primes[MAXN], cnt;
bool state[MAXN];

void init() {
  for (int i = 2; i < MAXN; i++) {
    if(!state[i]) primes[cnt++] = i;

    for (int j = 0; (ll)primes[j] * i < MAXN; j++) {
      state[primes[j] * i] = true;
      if (i % primes[j] == 0) break;
    }
  }
}

void solve() {
  init();

  int n, m; cin >> n >> m;
  vector<vi> a(n, vi(m));
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++) cin >> a[i][j];

  vector<vi> d(n, vi(m));  // 每个元素与它下一个素数的距离
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      int nxt = *lower_bound(primes, primes + cnt, a[i][j]);
      d[i][j] = nxt - a[i][j];
    }
  }

  int ans = INF;
  for (int i = 0; i < n; i++) {
    int res = 0;
    for (int j = 0; j < m; j++) res += d[i][j];
    ans = min(ans, res);
  }
  for (int j = 0; j < m; j++) {
    int res = 0;
    for (int i = 0; i < n; i++) res += d[i][j];
    ans = min(ans, res);
  }
  cout << ans;
}

int main() {
	solve();
}


284A. Cows and Primitive Roots

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

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

对一个素数 p p p,定义模 p p p意义下的原根为 [ 1 , p ) [1,p) [1,p)中的一个整数 x x x,使得 x − 1 , x 2 − 1 , ⋯   , x p − 2 − 1 x-1,x^2-1,\cdots,x^{p-2}-1 x1,x21,,xp21都不能被 p p p整除,但 x p − 1 x^{p-1} xp1能被 p p p整除.给定一个素数 p    ( 2 ≤ p ≤ 2000 ) p\ \ (2\leq p\leq 2000) p  (2p2000),求其原根的个数.

思路I

[ 1 , p ) [1,p) [1,p)的每个整数 x x x,枚举其 1 ∼ ( p − 2 ) 1\sim (p-2) 1(p2)次方和 ( p − 1 ) (p-1) (p1)次方,检查整除性即可,总时间复杂度 O ( p 2 ) O(p^2) O(p2).

代码I

void solve() {
  int p; cin >> p;

  int ans = 0;
  for (int i = 1; i < p; i++) {
    bool ok = true;
    int cur = 1;
    for (int j = 1; j <= p - 2; j++) {
      cur = cur * i % p;
      if ((cur - 1) % p == 0) {
        ok = false;
        break;
      }
    }
    if ((cur * i - 1) % p) ok = false;
    ans += ok;
  }
  cout << ans;
}

int main() {
	solve();
}

思路II

由原根存在性定理:素数存在原根.

g g g p p p的一个原根.考察集合 { g , g 2 , ⋯   , g p − 1 } \{g,g^2,\cdots,g^{p-1}\} {g,g2,,gp1}.若 g i g^i gi是原根,则 gcd ⁡ ( i , p − 1 ) = 1 \gcd(i,p-1)=1 gcd(i,p1)=1,则原根个数即 φ ( p − 1 ) \varphi(p-1) φ(p1),其中 φ ( n ) \varphi(n) φ(n)为Euler函数.

代码II

int phi(int x) {
  int res = x;
  for (int i = 2; i <= x / i; i++) {
    if (x % i == 0) {
      res = res / i * (i - 1);
      while (x % i == 0) x /= i;
    }
  }
  if (x > 1) res = res / x * (x - 1);
  return res;
}

void solve() {
  int p; cin >> p;

  cout << phi(p - 1);
}

int main() {
	solve();
}


337B. Routine Problem

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

题意

显示器的宽高比为 a : b a:b a:b,视频的宽高比为 c : d c:d c:d.先将视频放大或缩小使得它占据显示器尽量大的空间,求剩下的空间所占的比例,输出既约分数的形式.

第一行输入四个整数 a , b , c , d    ( 1 ≤ a , b , c , d ≤ 1000 ) a,b,c,d\ \ (1\leq a,b,c,d\leq 1000) a,b,c,d  (1a,b,c,d1000).

思路

设显示器的宽、高分别为 W W W H H H,则 W H = a b \dfrac{W}{H}=\dfrac{a}{b} HW=ba.设视频的宽、高分别为 w w w h h h,则. w h = c d \dfrac{w}{h}=\dfrac{c}{d} hw=dc

①若 a b < c d \dfrac{a}{b}<\dfrac{c}{d} ba<dc,则最优策略是视频与显示器同宽,此时放大倍数 k = W w k=\dfrac{W}{w} k=wW,视频的新高度为 h ′ = h W w = W d c h'=h\dfrac{W}{w}=\dfrac{Wd}{c} h=hwW=cWd.

a n s = H − h ′ H = W b a − W d c W b a = b c − a d b c ans=\dfrac{H-h'}{H}=\dfrac{\dfrac{Wb}{a}-\dfrac{Wd}{c}}{\dfrac{Wb}{a}}=\dfrac{bc-ad}{bc} ans=HHh=aWbaWbcWd=bcbcad.

②若 a b = c d \dfrac{a}{b}=\dfrac{c}{d} ba=dc,则视频恰能占满屏幕, a n s = 0 ans=0 ans=0,注意输出 0 / 1 0/1 0/1.

③若 a b > c d \dfrac{a}{b}>\dfrac{c}{d} ba>dc,最优策略是视频与显示器同高,此时视频的新宽度 w ′ = w H h = w W b a W d c = W b c a d w'=w\dfrac{H}{h}=w\dfrac{\dfrac{Wb}{a}}{\dfrac{Wd}{c}}=\dfrac{Wbc}{ad} w=whH=wcWdaWb=adWbc.

a n s = W − w ′ W = a d − b c a d ans=\dfrac{W-w'}{W}=\dfrac{ad-bc}{ad} ans=WWw=adadbc.

代码

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

  if (cmp((double)a / b, (double)c / d) == 0) cout << "0/1";
  else if (cmp((double)a / b, (double)c / d) < 0) {
    int up = b * c - a * d, down = b * c;
    int g = gcd(up, down);
    up /= g, down /= g;
    cout << up << '/' << down;
  }
  else {
    int up = a * d - b * c, down = a * d;
    int g = gcd(up, down);
    up /= g, down /= g;
    cout << up << '/' << down;
  }
}

int main() {
	solve();
}


337C. Quiz

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

题意

有连续 n n n个问题,玩家每答对一个问题获得 1 1 1分.有一个连续答对题数的计时器,答对一题时计时器 + 1 +1 +1,答错一题时计时器清零.若计时器达到 k k k,先将该问题回答正确的分数加到玩家的分数上后,玩家分数翻倍,同时计时器清零.现已知答对了 m m m个问题,求可获得的最小得分,答案对 1 e 9 + 9 1\mathrm{e}9+9 1e9+9取模.

第一行输入三个整数 n , m , k    ( 2 ≤ k ≤ n ≤ 1 e 9 , 0 ≤ m ≤ n ) n,m,k\ \ (2\leq k\leq n\leq 1\mathrm{e}9,0\leq m\leq n) n,m,k  (2kn1e9,0mn).

思路

显然应尽量避免翻倍,若无法避免,尽量在前面翻倍.

为充分利用答错的题数 w r o n g = n − m wrong=n-m wrong=nm,应在连续 ( k − 1 ) (k-1) (k1)个答对后放一个答错,则最少翻倍次数为 ⌊ n − k ( n − m ) k ⌋ \left\lfloor\dfrac{n-k(n-m)}{k}\right\rfloor knk(nm).

①若该值 ≤ 0 \leq 0 0,则可做到不翻倍, a n s = m ans=m ans=m.

②若该值 > 0 >0 >0,设第 i    ( i ≥ 1 ) i\ \ (i\geq 1) i  (i1)次翻倍后的分数为 f i f_i fi,初始条件 f 0 = 0 f_0=0 f0=0.

​ 易得递推公式 f i = 2 ( f i − 1 + k ) f_i=2(f_{i-1}+k) fi=2(fi1+k),展开后为等比数列求和,易得通项 f n = ( 2 n + 1 − 2 ) k f_n=(2^{n+1}-2)k fn=(2n+12)k.

​ 最后加上剩下的 n % k n\% k n%k道题的分数即可.

代码

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

  int wrong = n - m;
  if (n <= (ll)k * wrong) {
    cout << m;
    return;
  }

  n -= k * wrong;
  int x = n / k, y = n % k;
  int ans = (qpow(2, x + 1, MOD) - 2 + MOD) % MOD;  // 注意qpow(2, x + 1, MOD) - 2可能为负数
  ans = (((ll)ans * k % MOD + y) % MOD + (ll)(k - 1) * wrong % MOD) % MOD;
  cout << ans;
}

int main() {
	solve();
}


343A. Rational Resistance

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

题意

给定一个既约分数 a b    ( 1 ≤ a , b ≤ 1 e 18 ) \dfrac{a}{b}\ \ (1\leq a,b\leq 1\mathrm{e}18) ba  (1a,b1e18),求最少用多少个阻值为 1 1 1的定值电阻可串联或并联出一个电路使得其总阻值为 a b \dfrac{a}{b} ba.

思路

若能用 k k k个定值电阻构成阻值为 a b \dfrac{a}{b} ba的电路,则用 ( k + 1 ) (k+1) (k+1)个定值电阻能构成阻值为 a + b b \dfrac{a+b}{b} ba+b a a + b \dfrac{a}{a+b} a+ba的电路,即加入一个电阻相当于做一次Euclid算法的逆操作,故答案即Euclid算法的执行次数.

代码

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

	ll ans = 0;
	while (a && b) {
		if (a > b) {
			ans += a / b;
			a %= b;
		}
		else {
			ans += b / a;
			b %= a;
		}
	}
	cout << ans;
}

int main() {
	solve();
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值