Codeforces Round 875 (Div. 2)


A. Twin PermutationsPermalink

A. Twin Permutations

bi=n+1aib_i=n+1-a_i 로 두면 모든 수를 같게 만들 수 있다.

B. Array mergingPermalink

B. Array merging

정답은 aia_i 에서 연속된 kk 들과 bib_i 에서 kk 를 최대로 많이 써줄 수 있는 횟수이다.

혹은 bib_i에서 연속된 kk들과 aia_i 에서 kk를 최대로 많이 써줄 수 있는 횟수이다.

C. Copil Copac Draws TreesPermalink

C. Copil Copac Draws Trees

BFS를 돌리는데 간선의 가중치를 이전에 거쳐온 간선보다 현재 간선이 더 인덱스가 적다면 한 바퀴를 돌아야 하므로 +1+1 로 주고, 아니라면 00 으로줘서 최단경로중 가장 큰 것이 정답이다.

D. The BOSS Can Count PairsPermalink

D. The BOSS Can Count Pairs

aiaj=bi+bj2na_i \cdot a_j = b_i+b_j \le 2n 이기 때문에 Min(ai,aj)2n\text{Min}(a_i,a_j) \le \sqrt{ 2n }이다. S=2nS=\sqrt{ 2n }이라고 하자.

cnt(x,y)cnt(x,y)ai=x,bi=ya_i=x,b_i=y 인 것의 개수라고 두자, xSx \le S 인 경우만 저장해둔다.

따라서 map을 안쓰고 배열로 가능하다.

ai=aja_i=a_j 인경우를 세면,

i=0n1cnt(ai,ai2bi)s=1Scnt(s,s2/2)2\dfrac{\displaystyle \sum_{i=0}^{n-1}cnt(a_i,a_i^2-b_i)-\sum_{s=1}^{S}cnt(s,s^2/2)}{2} 이다.

모든 쌍에 대해 세준 후, i=ji=j 인 경우를 빼주고 i<ji<j 를 맞추기 위해 22로 나눠준 것이다.

이제 aiaja_i \neq a_j 인 경우를 세며, i<ji<j 란 조건을 ai<aja_i<a_j 로 바꿔도 무방하다.

Min(ai,aj)S\text{Min}(a_i, a_j) \le S 이기 때문에 j=0n1ai=1Min(aj1,2n/aj)cnt(ai,aiajbi)\displaystyle \sum_{j=0}^{n-1} \sum_{a_i=1}^{\text{Min}(a_j-1,\left\lfloor 2n/a_j \right\rfloor)}cnt(a_i,a_i \cdot a_j-b_i) 를 세줄 수 있다.

aiSa_i \le S여서 O(nn)O(n \sqrt{ n }) 으 시간복잡도가 나온다.

루트질을 할 생각은 했는데, ai=aja_i=a_j 인 경우를 따로 세준다음 빠르게 세줄 수 있는 것을 놓쳤다.

const int MAX = 2e5 + 5;  
int a[MAX], b[MAX], cnt[640][MAX];  
void solve() {  
   int n;  
   cin >> n;  
   int S = sqrt(n * 2);  
   for (int i = 0; i < n; i++) cin >> a[i];  
   for (int i = 0; i < n; i++) cin >> b[i];  
   for (int i = 0; i < n; i++) if (a[i] <= S) cnt[a[i]][b[i]]++;  
   ll ans = 0;  
   for (int i = 0; i < n; i++) {  
      if (a[i] <= S) {  
         if (a[i] * a[i] - b[i] >= 0 && a[i] * a[i] - b[i] <= n)  
            ans += cnt[a[i]][a[i] * a[i] - b[i]];  
      }  
   }  
   for (int s = 2; s <= S; s += 2) ans -= cnt[s][s * s / 2];  
   ans /= 2;  
   for (int i = 0; i < n; i++) {  
      for (int jv = 1; jv <= min(a[i] - 1, 2 * n / a[i]); jv++) {  
         assert(jv <= S);  
         if (jv * a[i] - b[i] >= 0 && jv * a[i] - b[i] <= n)  
            ans += cnt[jv][jv * a[i] - b[i]];  
      }  
   }  
   cout << ans << endl;  
   for (int i = 1; i <= n; i++) for (int j = 1; j <= S; j++) cnt[j][i] = 0;  
}

E. Hyperregular Bracket StringsPermalink

E. Hyperregular Bracket Strings

F. Mex TreePermalink

F. Mex Tree

Comments