[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≤1e5)n\ \ (2\leq n\leq 1\mathrm{e}5)n  (2n1e5)的序列a1,⋯ ,an  (1≤ai≤2e5)a_1,\cdots,a_n\ \ (1\leq a_i\leq 2\mathrm{e}5)a1,,an  (1ai2e5).求任意两下标不同的元素的lcm\mathrm{lcm}lcm构成的集合的gcd⁡\gcdgcd.

思路I

设素数ppp,则pk∣ansp^k\mid anspkans当且仅当a[]a[]a[]中至少有(n−1)(n-1)(n1)个元素是pkp^kpk的倍数.

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

(2)若a[]a[]a[]中至少有(n−1)(n-1)(n1)pkp^kpk的倍数,则任意两个ai,aja_i,a_jai,aj中至少有一个pkp^kpk的倍数,显然pk∣ansp^k\mid anspkans.

did_idia[]a[]a[]aia_iai外的元素构成的集合,则gcd⁡di\gcd d_igcddi至少能被(n−1)(n-1)(n1)a[]a[]a[]中的元素整除.

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

​ 此时ans=lcm(gcd⁡(d1),⋯ ,gcd⁡(dn))ans=\mathrm{lcm}(\gcd(d_1),\cdots,\gcd(d_n))ans=lcm(gcd(d1),,gcd(dn)).

考察如何求gcd⁡di\gcd d_igcddi.先求前缀gcd⁡\gcdgcd数组preipre_iprei和后缀gcd⁡\gcdgcd数组sufisuf_isufi,则gcd⁡di=gcd⁡(prei−1,sufi+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();
}


1350B. Orac and Models

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

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

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

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

思路

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

状态转移方程dp[i]=max⁡j∣i,sj<sifj+1\displaystyle dp[i]=\max_{j\mid i,s_j<s_i} f_j +1dp[i]=ji,sj<simaxfj+1.通过枚举倍数转移时间复杂度O(nlog⁡n)O(n\log n)O(nlogn),通过枚举约数转移时间复杂度O(nn)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();
}


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≤1e9)n,k\ \ (1\leq n,k\leq 1\mathrm{e}9)n,k  (1n,k1e9).设nnn的不大于kkk的最大约数为ddd,输出nd\dfrac{n}{d}dn.

思路

①若k≥nk\geq nkn,则ans=1ans=1ans=1;

②若nnn是素数,则ans=nans=nans=n.

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

代码

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();
}


1370C. Number Game

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

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

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

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

思路

(1)nnn为奇数时,

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

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

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

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

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

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

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

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

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

​ ii)若ppp非素数,则p=p1p2p=p_1p_2p=p1p2,其中p1p_1p1是素数,p2p_2p2>1>1>1的奇数.

​ Ashishgup第一步令n/=p2n/=p_2n/=p2,此时n=2p1n=2p_1n=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();
}


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≤1e9)n\ \ (2\leq n\leq 1\mathrm{e}9)n  (2n1e9).求两个正整数a,b s.t. a+b=na,b\ s.t.\ a+b=na,b s.t. a+b=n,且lcm(a,b)\mathrm{lcm}(a,b)lcm(a,b)最小.

思路

nnn的最大真约数为ddd,则取d,n−dd,n-dd,ndlcm(d,n−d)\mathrm{lcm}(d,n-d)lcm(d,nd)最小.

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

(1)下证:若k∣nk\mid nkn,则lcm(k,n−k)=n−k<n\mathrm{lcm}(k,n-k)=n-k<nlcm(k,nk)=nk<n.

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

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

​ 因lcm(a,b)=b\mathrm{lcm}(a,b)=blcm(a,b)=b当且仅当a∣ba\mid bab,则若k∤n,(n−k)k\not\mid n,(n-k)kn,(nk),则lcm(k,n−k)≠n−k\mathrm{lcm}(k,n-k)\neq n-klcm(k,nk)=nk.

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

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

代码

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();
}


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≤5e5,1≤m≤1e10)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. na+b−c=ma,b,c\in[l,r]\ s.t.\ na+b-c=ma,b,c[l,r] s.t. na+bc=m,输出任一组解.数据保证有解.

思路

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

固定b=lb=lb=lc=rc=rc=r.枚举aaa,则c−b=m%ac-b=m\% acb=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();
}


1396A. Multiples of Length

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

题意

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

思路

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

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

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

​ ②[1,n]+={0,−n⋅a2,−n⋅a3,⋯ ,−n⋅an}[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)⋅a2,(n−1)⋅a3,⋯ ,(n−1)⋅an}[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();
}


1397B. Power Sequence

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

题意

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

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

思路

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

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

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

∣ai−ci∣+∣aj−cj∣=max⁡{∣(ai+aj)−(ci+cj)∣,∣(ai−aj)−(ci−cj)∣}|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⁡{∣(aj+ai)−(ci+cj)∣,∣(aj−ai)−(ci−cj)∣}=∣aj−ci∣+∣ai−cj∣\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.

ai>aja_i>a_jai>ajci≤cjc^i\leq c^jcicj,故最小步数不增,进而最优策略是将a[]a[]a[]按非降序排列.

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

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

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

这样不会TLE的原因:注意到f(1)=∑i=0n−1(ai−1)<n⋅amax≤1e9⋅n\displaystyle f(1)=\sum_{i=0}^{n-1} (a_i-1)<n\cdot a_{max}\leq 1\mathrm{e}9\cdot nf(1)=i=0n1(ai1)<namax1e9n,

xn−1≤f(1)+amax≤1e9⋅(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,6n=3,4,5,6n=3,4,5,6时,max⁡(x)\max (x)max(x)分别不超过63245,1709,278,9363245,1709,278,9363245,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();
}


1401C. Mere Array

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

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

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

t  (1≤t≤1e4)t\ \ (1\leq t\leq 1\mathrm{e}4)t  (1t1e4)组测试数据.每组测试数据第一行输入一个整数n  (1≤n≤1e5)n\ \ (1\leq n\leq 1\mathrm{e}5)n  (1n1e5).第二行输入nnn个整数a1,⋯ ,an  (1≤ai≤1e9)a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}9)a1,,an  (1ai1e9).

思路

显然不是mmm的倍数的aia_iai位置不能修改.

mmm的倍数的aia_iai间可任意交换位置.

[] 设ax=m;m∣ay,aza_x=m;m\mid a_y,a_zax=m;may,az.为交换aya_yayaza_zaz,可先交换axa_xaxaya_yay,然后交换aya_yayaza_zaz,最后交换axa_xaxaza_zaz.

代码

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();
}


1407B. Big Vova

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

题意

给定一个长度为nnn的序列a1,⋯ ,ana_1,\cdots,a_na1,,an,将其排序为序列b1,⋯ ,bnb_1,\cdots,b_nb1,,bn,使得序列c1,⋯ ,cnc_1,\cdots,c_nc1,,cn的字典序最大,其中ci=gcd⁡1≤j≤ibj\displaystyle c_i=\gcd_{1\leq j\leq i} b_jci=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).第二行输入nnn个整数a1,⋯ ,an  (1≤ai≤1000)a_1,\cdots,a_n\ \ (1\leq a_i\leq 1000)a1,,an  (1ai1000).数据保证所有测试数据的nnn之和不超过100010001000.

思路I

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

设此时已放了(k−1)(k-1)(k1)个元素,现令bk=aj s.t. ck=gcd⁡(b1,⋯ ,bk−1,aj)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[]的字典序最大.

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

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

nnn次操作,第iii次操作时在a[]a[]a[]剩下的元素中选一个aj s.t. gcd(aj,ci−1)a_j\ s.t.\ gcd(a_j,c_{i-1})aj s.t. gcd(aj,ci1)最大,令bi=ajb_i=a_jbi=aj.

iii次操作的时间复杂度为O((n−i)log⁡A)O((n-i)\log A)O((ni)logA),其中A=max⁡1≤i≤nai\displaystyle A=\max_{1\leq i\leq n}a_iA=1inmaxai,总时间复杂度O(n2log⁡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();
}

思路II

设序列a[]a[]a[]中有cntxcnt_xcntx个元素为xxx.用cnt[]cnt[]cnt[],每次操作可在O(Alog⁡A)O(A\log A)O(AlogA)的时间复杂度内找到最优的bkb_kbk,总时间复杂度O(Anlog⁡A)O(An\log A)O(AnlogA).


思路III

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

设当前已将a[]a[]a[]中的kkk个元素放入b[]b[]b[]中,ck=gcd⁡(b1,⋯ ,bk)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⁡(ck,x)x\ s.t.\ \gcd(c_k,x)x s.t. gcd(ck,x)最大,

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值