• [Codeforces] number theory (R1600) Part.9


    [Codeforces] number theory (R1600) Part.9

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

    1349A. Orac and LCM

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

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

    给定一个长度为 n    ( 2 ≤ n ≤ 1 e 5 ) n\ \ (2\leq n\leq 1\mathrm{e}5) n  (2n1e5)的序列 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ 2 e 5 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 2\mathrm{e}5) a1,,an  (1ai2e5).求任意两下标不同的元素的 l c m \mathrm{lcm} lcm构成的集合的 gcd ⁡ \gcd gcd.

    思路I

    设素数 p p p,则 p k ∣ a n s p^k\mid ans pkans当且仅当 a [ ] a[] a[]中至少有 ( n − 1 ) (n-1) (n1)个元素是 p k p^k pk的倍数.

    [] (1)若 a [ ] a[] a[]中只有 ( n − 2 ) (n-2) (n2) p k p^k pk的倍数,则 ∃ x , y   s . t .   p k ∤ a x , p k ∤ a y \exists x,y\ s.t.\ p^k\not\mid a_x,p^k\not\mid a_y x,y s.t. pkax,pkay,进而 p k ∤ l c m ( a x , a y ) p^k\not\mid \mathrm{lcm}(a_x,a_y) pklcm(ax,ay),则 p k ∤ a n s p^k\not\mid ans pkans.

    (2)若 a [ ] a[] a[]中至少有 ( n − 1 ) (n-1) (n1) p k p^k pk的倍数,则任意两个 a i , a j a_i,a_j ai,aj中至少有一个 p k p^k pk的倍数,显然 p k ∣ a n s p^k\mid ans pkans.

    d i d_i di a [ ] a[] a[] a i a_i ai外的元素构成的集合,则 gcd ⁡ d i \gcd d_i gcddi至少能被 ( n − 1 ) (n-1) (n1) a [ ] a[] a[]中的元素整除.

    a [ ] a[] a[]中至少有 ( n − 1 ) (n-1) (n1)个元素是 p k p^k pk的倍数,则 ∃ i   s . t .   p k ∣ gcd ⁡ d i \exists i\ s.t.\ p^k\mid \gcd d_i i s.t. pkgcddi,

    ​ 此时 a n s = l c m ( gcd ⁡ ( d 1 ) , ⋯   , gcd ⁡ ( d n ) ) ans=\mathrm{lcm}(\gcd(d_1),\cdots,\gcd(d_n)) ans=lcm(gcd(d1),,gcd(dn)).

    考察如何求 gcd ⁡ d i \gcd d_i gcddi.先求前缀 gcd ⁡ \gcd gcd数组 p r e i pre_i prei和后缀 gcd ⁡ \gcd gcd数组 s u f i suf_i sufi,则 gcd ⁡ d i = gcd ⁡ ( p r e i − 1 , s u f i + 1 ) \gcd d_i=\gcd(pre_{i-1},suf_{i+1}) gcddi=gcd(prei1,sufi+1).

    代码I

    const int MAXN = 1e5 + 5;
    int n;
    int a[MAXN];
    int pre[MAXN], suf[MAXN];  // 前缀gcd、后缀gcd
    
    void solve() {
      cin >> n;
      for (int i = 1; i <= n; i++) cin >> a[i];
    
      for (int i = 1; i <= n; i++) pre[i] = gcd(pre[i - 1], a[i]);
      for (int i = n; i >= 1; i--) suf[i] = gcd(suf[i + 1], a[i]);
    
      ll ans = 1;
      for (int i = 1; i <= n; i++) 
        ans = lcm(ans, gcd(pre[i - 1], suf[i + 1]));
      cout << ans;
    }
    
    int main() {
      solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21


    1350B. Orac and Models

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

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

    有编号 1 ∼ n 1\sim n 1n n n n个物品,大小分别为 s 1 , ⋯   , s n s_1,\cdots,s_n s1,,sn.现要从中依次选若干个物品组成一个序列,即选中的物品编号升序.称构成的序列是好的,如果对相邻的选中物品的编号 i j i_j ij i j + 1 i_{j+1} ij+1,有 i j ∣ i j + 1 i_j\mid i_{j+1} ijij+1,且 s i j < s i j + 1 s_{i_j}sij<sij+1.特别地,只包含一个物品的序列也是好的.求好的序列的长度的最大值.

    t    ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t  (1t100)组测试数据.每组测试数据第一行输入一个整数 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5).第二行输入 n n n个整数 s 1 , ⋯   , s n    ( 1 ≤ s i ≤ 1 e 9 ) s_1,\cdots,s_n\ \ (1\leq s_i\leq 1\mathrm{e}9) s1,,sn  (1si1e9).数据保证所有测试数据的 n n n之和不超过 1 e 5 1\mathrm{e}5 1e5.

    思路

    d p [ i ] dp[i] dp[i]表示以第 i i i个物品结尾的好的序列的长度的最大值,则 a n s = max ⁡ 1 ≤ i ≤ n d p [ i ] \displaystyle ans=\max_{1\leq i\leq n}dp[i] ans=1inmaxdp[i].

    状态转移方程 d p [ i ] = max ⁡ j ∣ i , s j < s i f j + 1 \displaystyle dp[i]=\max_{j\mid i,s_jdp[i]=ji,sj<simaxfj+1.通过枚举倍数转移时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn),通过枚举约数转移时间复杂度 O ( n n ) O(n\sqrt{n}) O(nn ).

    代码

    const int MAXN = 1e5 + 5;
    int n;
    int s[MAXN];
    int dp[MAXN];  // dp[i]表示以第i个物品结尾的好的序列的长度的最大值
    
    void solve() {
      cin >> n;
      for (int i = 1; i <= n; i++) {
        cin >> s[i];
        dp[i] = 1;  // 清空
      }
    
      for (int i = 1; i <= n; i++) {
        for (int j = 2 * i; j <= n; j += i)
          if (s[i] < s[j]) dp[j] = max(dp[j], dp[i] + 1);
      }
    
      cout << *max_element(dp + 1, dp + n + 1) << endl;
    }
    
    int main() {
      CaseT  // 单测时注释掉该行
        solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24


    1360D. Buying Shovels

    原题指路:https://codeforces.com/problemset/problem/1360/D

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

    t    ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t  (1t100)组测试数据.每组测试数据输入两个整数 n , k    ( 1 ≤ n , k ≤ 1 e 9 ) n,k\ \ (1\leq n,k\leq 1\mathrm{e}9) n,k  (1n,k1e9).设 n n n的不大于 k k k的最大约数为 d d d,输出 n d \dfrac{n}{d} dn.

    思路

    ①若 k ≥ n k\geq n kn,则 a n s = 1 ans=1 ans=1;

    ②若 n n n是素数,则 a n s = n ans=n ans=n.

    ③枚举 n n n ≤ n \leq\sqrt{n} n 的约数 d d d,检查是否有 n d ≤ k \dfrac{n}{d}\leq k dnk.

    代码

    bool check(int n) {  // 判断素数
      if (n <= 2) return n == 2;
    
      for (int i = 2; (ll)i * i <= n; i++)
        if (n % i == 0) return false;
      return true;
    }
    
    void solve() {
      int n, k; cin >> n >> k;
    
      if (k >= n) cout << 1 << endl;
      else if (check(n)) cout << n << endl;
      else {
        int ans = n;
        for (int i = 1; (ll)i * i <= n && i <= k; i++) {
          if (n % i == 0) {
            if (i <= k) ans = min(ans, n / i);
            if (n / i <= k) ans = min(ans, i);
          }
        }
        cout << ans << endl;
      }
    }
    
    int main() {
      CaseT  // 单测时注释掉该行
        solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29


    1370C. Number Game

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

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

    Ashishgup和FastestFinger玩游戏,Ashishgup先手.初始时给定一个整数 n n n.每轮每人需进行如下两个操作之一:①设 d d d n n n > 1 >1 >1的奇约数,令 n / = d n/=d n/=d;②若 n > 1 n>1 n>1,令 n − − n-- n,无法操作者负.两人都采取最优策略,问谁胜.

    t    ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t  (1t100)组测试数据.每组测试数据输入一个整数 n    ( 1 ≤ n ≤ 1 e 9 ) n\ \ (1\leq n\leq 1\mathrm{e}9) n  (1n1e9).

    思路

    (1) n n n为奇数时,

    ​ ①若 n = 1 n=1 n=1,则Ashishgup第一步无法操作,FastestFinger胜.

    ​ ②若 n ≥ 3 n\geq 3 n3,则Ashishgup第一步令 n / = n n/=n n/=n,则FastestFinger无法操作,Ashishgup胜.

    (2) n n n为偶数且 n n n > 1 >1 >1的奇约数时,显然 n n n只能是 2 2 2的幂次.

    ​ ① n = 2 n=2 n=2时,Ashishgup胜.

    ​ ② n ≥ 4 n\geq 4 n4时,Ashishgup第一步只能令 n − − n-- n使其变为 ≥ 3 \geq 3 3的奇数,此时FastestFinger胜.

    (3) n n n为偶数且有奇约数时,

    ​ ①若 4 ∣ n 4\mid n 4n,则Ashishgup第一步令 n n n除以其最大的奇约数使其变为 2 x    ( x > 1 ) 2^x\ \ (x>1) 2x  (x>1),此时Ashishgup胜.

    ​ ②设 n = 2 p n=2p n=2p,其中 p p p为奇数.

    ​ i)若 p p p为素数,无论Ashishgup第一步选哪个操作都会使其变为必败态,此时FastestFinger胜.

    ​ ii)若 p p p非素数,则 p = p 1 p 2 p=p_1p_2 p=p1p2,其中 p 1 p_1 p1是素数, p 2 p_2 p2 > 1 >1 >1的奇数.

    ​ Ashishgup第一步令 n / = p 2 n/=p_2 n/=p2,此时 n = 2 p 1 n=2p_1 n=2p1,此时Ashishgup胜.

    代码

    bool check(int n) {  // 判断素数
      if (n <= 2) return n == 2;
    
      for (int i = 2; (ll)i * i <= n; i++)
        if (n % i == 0) return false;
      return true;
    }
    
    void solve() {
      int n; cin >> n;
    
      bool ok = true;
      if (n == 1) ok = false;
      if (n % 2 == 0 && (n & (n - 1)) == 0 && n >= 4) ok = false;
      if (n % 2 == 0 && n % 4 && check(n / 2)) ok = false;
    
      cout << (ok ? "Ashishgup" : "FastestFinger") << endl;
    }
    
    int main() {
      CaseT  // 单测时注释掉该行
        solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23


    1372B. Omkar and Last Class of Math

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

    题意

    t    ( 1 ≤ t ≤ 10 ) t\ \ (1\leq t\leq 10) t  (1t10)组测试数据.每组测试数据输入一个整数 n    ( 2 ≤ n ≤ 1 e 9 ) n\ \ (2\leq n\leq 1\mathrm{e}9) n  (2n1e9).求两个正整数 a , b   s . t .   a + b = n a,b\ s.t.\ a+b=n a,b s.t. a+b=n,且 l c m ( a , b ) \mathrm{lcm}(a,b) lcm(a,b)最小.

    思路

    n n n的最大真约数为 d d d,则取 d , n − d d,n-d d,nd l c m ( d , n − d ) \mathrm{lcm}(d,n-d) lcm(d,nd)最小.

    [] 设最优解为 k k k ( n − k ) (n-k) (nk).不失一般性,不妨设 k ≤ n − k k\leq n-k knk,则 n − k ≥ n 2 n-k\geq \dfrac{n}{2} nk2n.

    (1)下证:若 k ∣ n k\mid n kn,则 l c m ( k , n − k ) = n − k < n \mathrm{lcm}(k,n-k)=n-klcm(k,nk)=nk<n.

    ​ 设 n = m k n=mk n=mk,则 n − k = ( m − 1 ) k n-k=(m-1)k nk=(m1)k,此时 l c m ( k , n − k ) = n − k \mathrm{lcm}(k,n-k)=n-k lcm(k,nk)=nk.

    (2)下证:若 k ∤ n k\not\mid n kn,则 l c m ( k , n − k ) > n \mathrm{lcm}(k,n-k)>n lcm(k,nk)>n.

    ​ 因 l c m ( a , b ) = b \mathrm{lcm}(a,b)=b lcm(a,b)=b当且仅当 a ∣ b a\mid b ab,则若 k ∤ n , ( n − k ) k\not\mid n,(n-k) kn,(nk),则 l c m ( k , n − k ) ≠ n − k \mathrm{lcm}(k,n-k)\neq n-k lcm(k,nk)=nk.

    ​ 因 l c m ( k , n − k ) \mathrm{lcm}(k,n-k) lcm(k,nk) ( n − k ) (n-k) (nk)的倍数,则 l c m ( k , n − k ) ≥ 2 ( n − k ) ≥ 2 ⋅ n 2 = n \mathrm{lcm}(k,n-k)\geq 2(n-k)\geq 2\cdot\dfrac{n}{2}=n lcm(k,nk)2(nk)22n=n.

    故为使得 l c m ( k , n − k ) \mathrm{lcm}(k,n-k) lcm(k,nk)最小, k k k应取 n n n的非自身的最大约数.

    代码

    void solve() {
      int n; cin >> n;
    
      for (int i = 2; (ll)i * i <= n; i++) {
        if (n % i == 0) {
          int ans = n / i;
          cout << ans << ' ' << n - ans << endl;
          return;
        }
      }
      cout << 1 << ' ' << n - 1 << endl;
    }
    
    int main() {
      CaseT  // 单测时注释掉该行
        solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17


    1379B. Dubious Cyrpto

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

    题意

    t    ( 1 ≤ t ≤ 20 ) t\ \ (1\leq t\leq 20) t  (1t20)组测试数据.每组测试数据输入三个整数 l , r , m    ( 1 ≤ l ≤ r ≤ 5 e 5 , 1 ≤ m ≤ 1 e 10 ) l,r,m\ \ (1\leq l\leq r\leq 5\mathrm{e}5,1\leq m\leq 1\mathrm{e}10) l,r,m  (1lr5e5,1m1e10).求三个整数 a , b , c ∈ [ l , r ]   s . t .   n a + b − c = m a,b,c\in[l,r]\ s.t.\ na+b-c=m a,b,c[l,r] s.t. na+bc=m,输出任一组解.数据保证有解.

    思路

    显然可以用 O ( t ( r − l ) ) O(t(r-l)) O(t(rl))的时间复杂度通过.

    固定 b = l b=l b=l c = r c=r c=r.枚举 a a a,则 c − b = m % a c-b=m\% a cb=m%a,检查答案是否在区间 [ l , r ] [l,r] [l,r]中即可.

    代码

    void solve() {
      int l, r; ll m; cin >> l >> r >> m;
    
      for (int a = l; a <= r; a++) {
        int p = a - m % a;  // c-b
        if (l + p <= r) {
          cout << a << ' ' << l << ' ' << l + p << endl;
          return;
        }
        else if (r - p >= l) {
          cout << a << ' ' << r - p << ' ' << r << endl;
          return;
        }
    
        p = a - p;
        if (l + p <= r) {
          cout << a << ' ' << l + p << ' ' << l << endl;
          return;
        }
        else if (r - p >= l) {
          cout << a << ' ' << r << ' ' << r - p << endl;
          return;
        }
      }
    }
    
    int main() {
      CaseT  // 单测时注释掉该行
        solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30


    1396A. Multiples of Length

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

    题意

    给定一个长度为 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5)的序列 a 1 , ⋯   , a n    ( − 1 e 9 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (-1\mathrm{e}9\leq a_i\leq 1\mathrm{e}9) a1,,an  (1e9ai1e9).现有操作:选择 a [ ] a[] a[]中的一个区间,区间中的每个数加上 l e n len len的某个倍数(可不同),其中 l e n len len为区间长度.构造三个操作,使得操作后 a [ ] a[] a[]的所有元素变为 0 0 0,若有多组解,输出任一组.

    思路

    (1) n = 1 n=1 n=1时,操作:① [ 1 , 1 ] + = 0 [1,1]+=0 [1,1]+=0;② [ 1 , 1 ] + = 0 [1,1]+=0 [1,1]+=0;③ [ 1 , 1 ] + = − a 1 [1,1]+=-a_1 [1,1]+=a1.

    (2) n ≥ 2 n\geq 2 n2时,操作:

    ​ ① [ 1 , 1 ] + = − a 1 [1,1]+=-a_1 [1,1]+=a1.

    ​ ② [ 1 , n ] + = { 0 , − n ⋅ a 2 , − n ⋅ a 3 , ⋯   , − n ⋅ a n } [1,n]+=\{0,-n\cdot a_2,-n\cdot a_3,\cdots,-n\cdot a_n\} [1,n]+={0,na2,na3,,nan}.

    ​ ③ [ 2 , n ] + = { ( n − 1 ) ⋅ a 2 , ( n − 1 ) ⋅ a 3 , ⋯   , ( n − 1 ) ⋅ a n } [2,n]+=\{(n-1)\cdot a_2,(n-1)\cdot a_3,\cdots,(n-1)\cdot a_n\} [2,n]+={(n1)a2,(n1)a3,,(n1)an}.

    代码

    void solve() {
      int n; cin >> n;
      vi a(n);
      for (auto& ai : a) cin >> ai;
    
      if (n == 1) {
        cout << "1 1" << endl;
        cout << 0 << endl;
        cout << "1 1" << endl;
        cout << 0 << endl;
        cout << "1 1" << endl;
        cout << -a[0] << endl;
      }
      else {
        cout << "1 1" << endl;
        cout << -a[0] << endl;
    
        cout << "1 " << n << endl;
        cout << 0 << ' ';
        for (int i = 1; i < n; i++) cout << (ll)-n * a[i] << ' ';
        cout << endl;
    
        cout << "2 " << n << endl;
        for (int i = 1; i < n; i++) cout << (ll)(n - 1) * a[i] << ' ';
        cout << endl;
      }
    }
    
    int main() {
      solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31


    1397B. Power Sequence

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

    题意

    称一个长度为 n n n的序列 a 0 , ⋯   , a n − 1 a_0,\cdots,a_{n-1} a0,,an1是好的,如果对 ∀ i ∈ [ 0 , n − 1 ] \forall i\in[0,n-1] i[0,n1],都有 a i = c i a_i=c^i ai=ci,其中 c ∈ Z + c\in\mathbb{Z}^+ cZ+.

    给定一个长度为 n    ( 3 ≤ n ≤ 1 e 5 ) n\ \ (3\leq n\leq 1\mathrm{e5}) n  (3n1e5)的序列 a 0 , ⋯   , a n − 1    ( 1 ≤ a i ≤ 1 e 9 ) a_0,\cdots,a_{n-1}\ \ (1\leq a_i\leq 1\mathrm{e}9) a0,,an1  (1ai1e9).现有如下两种操作:①将序列重新排序;②选一个下标 i i i,令 a i − − a_i-- ai a i + + a_i++ ai++.求将序列 a [ ] a[] a[]变为好的序列的最小操作次数.

    思路

    操作①的最优策略是将 a [ ] a[] a[]按非降序排列.

    [] 将 a i a_i ai变为 c i c^i ci的代价为 ∣ a i − c i ∣ |a_i-c^i| aici.

    若存在一对 ( i , j )   s . t .   i < j (i,j)\ s.t.\ i(i,j) s.t. i<j a i > a j a_i>a_j ai>aj,交换 a i a_i ai a j a_j aj后,由 ∣ x ∣ + ∣ y ∣ = max ⁡ { ∣ x + y ∣ , ∣ x − y ∣ } |x|+|y|=\max\{|x+y|,|x-y|\} x+y=max{x+y,xy}知:

    ∣ a i − c i ∣ + ∣ a j − c j ∣ = max ⁡ { ∣ ( a i + a j ) − ( c i + c j ) ∣ , ∣ ( a i − a j ) − ( c i − c j ) ∣ } |a_i-c^i|+|a_j-c^j|=\max\{|(a_i+a_j)-(c^i+c^j)|,|(a_i-a_j)-(c^i-c^j)|\} aici+ajcj=max{(ai+aj)(ci+cj),(aiaj)(cicj)}

    ≥ max ⁡ { ∣ ( a j + a i ) − ( c i + c j ) ∣ , ∣ ( a j − a i ) − ( c i − c j ) ∣ } = ∣ a j − c i ∣ + ∣ a i − c j ∣ \geq \max\{|(a_j+a_i)-(c^i+c^j)|,|(a_j-a_i)-(c^i-c^j)|\}=|a_j-c^i|+|a_i-c^j| max{(aj+ai)(ci+cj),(ajai)(cicj)}=ajci+aicj.

    a i > a j a_i>a_j ai>aj c i ≤ c j c^i\leq c^j cicj,故最小步数不增,进而最优策略是将 a [ ] a[] a[]按非降序排列.

    a [ ] a[] a[]按非降序排列,设 a m a x = a n − 1 a_{max}=a_{n-1} amax=an1.将 a [ ] a[] a[]变为好的序列所需的步数为 f ( x ) = ∑ i = 0 n − 1 ∣ a i − x i ∣ \displaystyle f(x)=\sum_{i=0}^{n-1}|a_i-x^i| f(x)=i=0n1aixi,其中 f ( c ) f(c) f(c)是最小步数.

    注意到 c n − 1 − a m a x ≤ f ( c ) ≤ f ( 1 ) c^{n-1}-a_{max}\leq f(c)\leq f(1) cn1amaxf(c)f(1),则 c n − 1 ≤ f ( 1 ) + a m a x c^{n-1}\leq f(1)+a_{max} cn1f(1)+amax.

    遍历 x = 1 , 2 , ⋯ x=1,2,\cdots x=1,2,直至 x n − 1 > f ( 1 ) + a m a x x^{n-1}>f(1)+a_{max} xn1>f(1)+amax,对每个 x x x线性地求 f ( n ) f(n) f(n),更新最小答案即可,总时间复杂度 O ( n ⋅ max ⁡ ( x ) ) O(n\cdot \max(x)) O(nmax(x)).

    这样不会TLE的原因:注意到 f ( 1 ) = ∑ i = 0 n − 1 ( a i − 1 ) < n ⋅ a m a x ≤ 1 e 9 ⋅ n \displaystyle f(1)=\sum_{i=0}^{n-1} (a_i-1)f(1)=i=0n1(ai1)<namax1e9n,

    x n − 1 ≤ f ( 1 ) + a m a x ≤ 1 e 9 ⋅ ( n + 1 ) x^{n-1}\leq f(1)+a_{max}\leq 1\mathrm{e}9\cdot (n+1) xn1f(1)+amax1e9(n+1). n = 3 , 4 , 5 , 6 n=3,4,5,6 n=3,4,5,6时, max ⁡ ( x ) \max (x) max(x)分别不超过 63245 , 1709 , 278 , 93 63245,1709,278,93 63245,1709,278,93,故可过.

    注意可能爆ll,但爆ll的显然不是最优解.

    代码

    ll add(ll a, ll b) { return a + b < INFF ? a + b : INFF; }
    
    ll mul(ll a, ll b) { return INFF / a > b ? a * b : INFF; }
    
    void solve() {
      int n; cin >> n;
      vi a(n);
      for (auto& ai : a) cin >> ai;
      sort(all(a));
    
      ll ans = accumulate(all(a), (ll)0) - n;
      for (int x = 1;; x++) {
        ll cur = 1, res = 0;
        for (int i = 0; i < n; i++) {
          res = add(res, abs(a[i] - cur));
          cur = mul(cur, x);
        }
    
        if (cur == INFF || cur / x > ans + a[n - 1]) break;
        ans = min(ans, res);
      }
      cout << ans;
    }
    
    int main() {
      solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27


    1401C. Mere Array

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

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

    给定一个长度为 n n n的序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an.现有操作:设序列最小元素为 m m m.选择两个下标 i , j ∈ [ 1 , n ]   s . t .   gcd ⁡ ( a i , a j ) = m i,j\in [1,n]\ s.t.\ \gcd(a_i,a_j)=m i,j[1,n] s.t. gcd(ai,aj)=m,则交换 a i a_i ai a j a_j aj.若经若干次操作可使得 a [ ] a[] a[]非降序,则输出"YES";否则输出"NO".

    t    ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t  (1t1e4)组测试数据.每组测试数据第一行输入一个整数 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5).第二行输入 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).

    思路

    显然不是 m m m的倍数的 a i a_i ai位置不能修改.

    m m m的倍数的 a i a_i ai间可任意交换位置.

    [] 设 a x = m ; m ∣ a y , a z a_x=m;m\mid a_y,a_z ax=m;may,az.为交换 a y a_y ay a z a_z az,可先交换 a x a_x ax a y a_y ay,然后交换 a y a_y ay a z a_z az,最后交换 a x a_x ax a z a_z az.

    代码

    void solve() {
      int n; cin >> n;
      vi a(n), tmpa(n);
      int m = INFF;  // a[]的最小元素
      for (int i = 0; i < n; i++) {
        cin >> a[i];
        tmpa[i] = a[i];
        m = min(m, a[i]);
      }
    
      sort(all(tmpa));
    
      for (int i = 0; i < n; i++) {
        if (a[i] != tmpa[i] && a[i] % m) {
          cout << "NO" << endl;
          return;
        }
      }
      cout << "YES" << endl;
    }
    
    int main() {
      CaseT  // 单测时注释掉该行
        solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25


    1407B. Big Vova

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

    题意

    给定一个长度为 n n n的序列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an,将其排序为序列 b 1 , ⋯   , b n b_1,\cdots,b_n b1,,bn,使得序列 c 1 , ⋯   , c n c_1,\cdots,c_n c1,,cn的字典序最大,其中 c i = gcd ⁡ 1 ≤ j ≤ i b j \displaystyle c_i=\gcd_{1\leq j\leq i} b_j ci=1jigcdbj.若有多组解,输出任一组.

    t    ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t  (1t1000)组测试数据.每组测试数据第一行输入一个整数 n    ( 1 ≤ n ≤ 1000 ) n\ \ (1\leq n\leq 1000) n  (1n1000).第二行输入 n n n个整数 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ 1000 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1000) a1,,an  (1ai1000).数据保证所有测试数据的 n n n之和不超过 1000 1000 1000.

    思路I

    设初始时 b [ ] b[] b[]为空,现依次将 a [ ] a[] a[]中的元素放到 b [ ] b[] b[]中.

    设此时已放了 ( k − 1 ) (k-1) (k1)个元素,现令 b k = a j   s . t .   c k = gcd ⁡ ( b 1 , ⋯   , b k − 1 , a j ) b_k=a_j\ s.t.\ c_k=\gcd(b_1,\cdots,b_{k-1},a_j) bk=aj s.t. ck=gcd(b1,,bk1,aj)最大,显然这样 c [ ] c[] c[]的字典序最大.

    事实上,解与 b k b_k bk的具体值无关,因为每个 c j c_j cj都整除 c j − 1 c_{j-1} cj1,则 gcd ⁡ ( b k , c j ) = gcd ⁡ ( c k , c j )    ( j ≥ k ) \gcd(b_k,c_j)=\gcd(c_k,c_j)\ \ (j\geq k) gcd(bk,cj)=gcd(ck,cj)  (jk).

    设有备用元素 c 0 = 0 c_0=0 c0=0,则对 ∀ k ≥ 1 \forall k\geq 1 k1,有 gcd ⁡ ( 0 , k ) = k \gcd(0,k)=k gcd(0,k)=k.

    n n n次操作,第 i i i次操作时在 a [ ] a[] a[]剩下的元素中选一个 a j   s . t .   g c d ( a j , c i − 1 ) a_j\ s.t.\ gcd(a_j,c_{i-1}) aj s.t. gcd(aj,ci1)最大,令 b i = a j b_i=a_j bi=aj.

    i i i次操作的时间复杂度为 O ( ( n − i ) log ⁡ A ) O((n-i)\log A) O((ni)logA),其中 A = max ⁡ 1 ≤ i ≤ n a i \displaystyle A=\max_{1\leq i\leq n}a_i A=1inmaxai,总时间复杂度 O ( n 2 log ⁡ A ) O(n^2\log A) O(n2logA).

    代码I

    void solve() {
      int n; cin >> n;
      vi a(n);
      int minidx = 0;
      for (int i = 0; i < n; i++) {
        cin >> a[i];
        if (a[i] > a[minidx]) minidx = i;
      }
    
      vi b(n);
      b[0] = a[minidx], a[minidx] = 0;
    
      int cgcd = b[0];
      for (int i = 1; i < n; i++) {
        int cidx = 0, cans = 0;  // 要选择的a[j]的下标j、最大c[i]
        for (int j = 0; j < n; j++) {
          if (a[j] && gcd(a[j], cgcd) > cans) {
            cans = gcd(a[j], cgcd);
            cidx = j;
          }
        }
    
        b[i] = a[cidx], a[cidx] = 0;
        cgcd = cans;
      }
    
      for (int i = 0; i < n; i++) cout << b[i] << " \n"[i == n - 1];
    }
    
    int main() {
      CaseT  // 单测时注释掉该行
        solve();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    思路II

    设序列 a [ ] a[] a[]中有 c n t x cnt_x cntx个元素为 x x x.用 c n t [ ] cnt[] cnt[],每次操作可在 O ( A log ⁡ A ) O(A\log A) O(AlogA)的时间复杂度内找到最优的 b k b_k bk,总时间复杂度 O ( A n log ⁡ A ) O(An\log A) O(AnlogA).


    思路III

    注意到对 ∀ i > 1 \forall i>1 i>1,要么 c i = c i − 1 c_i=c_{i-1} ci=ci1,要么 2 c i ≤ c i − 1 2c_i\leq c_{i-1} 2cici1,这表明 c [ ] c[] c[]只有 O ( log ⁡ A ) O(\log A) O(logA)种不同取值.

    设当前已将 a [ ] a[] a[]中的 k k k个元素放入 b [ ] b[] b[]中, c k = gcd ⁡ ( b 1 , ⋯   , b k ) c_k=\gcd(b_1,\cdots,b_k) ck=gcd(b1,,bk).

    O ( log ⁡ A ) O(\log A) O(logA)次操作,每次操作在 a [ ] a[] a[]剩下的元素中选一个 x   s . t .   gcd ⁡ ( c k , x ) x\ s.t.\ \gcd(c_k,x) x s.t. gcd(ck,x)最大,

    ​ 将 a [ ] a[] a[]中所有值为 x x x的元素放入 b [ ] b[] b[]中.每次操作时间复杂度 O ( n log ⁡ A ) O(n\log A) O(nlogA),总时间复杂度 O ( n log ⁡ 2 A ) O(n\log^2 A) O(nlog2A).



  • 相关阅读:
    Go通过reflect.Value修改值
    2022_08_09__106期__二叉树
    String字符串的常用方法
    华为机试:最小传输时延
    FreeRTos延时函数xTaskDelayUntil的工作原理
    discuzQ安装
    TwinCAT3添加伺服控制器的方法
    stm32项目平衡车详解(stm32F407)下
    linux 音视频架构 linux音视频开发
    开源酒店预订订房小程序源码系统+多元商户 前端+后端完整搭建教程 可二次开发
  • 原文地址:https://blog.csdn.net/Hytidel/article/details/127130197