BOJ 10370 - Ball

BOJ 28261 와 비슷한 이항계수 조합론 문제이다.

W=0,R=1,G=2W=0, R=1, G=2 로 나타내면 한 턴이 지난 후에 f(x,y)=(x+y)(mod3)f(x,y)=(x+y) \pmod 3 이 된다.

이 꼴이 이항계수처럼 나오는데,

한 턴이 지나면 ii 번째 자리가 ai+ai+1a_i+a_{i+1}이 되고,

두턴이 지나면 ai+2ai+1+ai+2a_i+2a_{i+1}+a_{i+2}가 되고 세턴이 지나면

ai+3ai+1+3ai+2+ai+3a_i+3a_{i+1}+3a_{i+2}+a_{i+3} 이 된다.

그런데 우린 33으로 나눈 나머지가 필요하므로 ai+ai+3a_i+a_{i+3}이 된다.

이항계수 (nk)\dbinom{n}{k}에서 nn33의 거듭제곱 수일 때, 항상 (n0)=(nn)=1\dbinom{n}{0}=\dbinom{n}{n}=1 을 제외하고 모두 33의 배수이다.

\because (nk)=n(n1)(nk+1)k!\dbinom{n}{k}=\dfrac{n(n-1) \cdots (n-k+1)}{k!} 여서 항상 nn33이 하나이상 남기 때문이다. 분모에서 33의 거듭제곱 지수가 분자에있는 것보다 이상이 될 수 없다.

따라서 n3kn \ge 3^kkk를 계속 골라가며 aiai+ai+3k(mod3)a_i \coloneqq a_i+a_{i+3^k} \pmod 3 을 진행하고 nn에서 3k3^k 를 빼는것을 반복한다.

이 횟수는 O(log3n)O(\log_3 n) 이 걸리고 문제를 O(TSlog3N)O(T \cdot \vert S \vert \cdot \log_3 N) 에 해결할 수 있다.

const ll mod = 3;  
inline ll md(ll x) { return md(mod, x); }  
int idx(char c) {  
   return c == 'W' ? 0 : c == 'R' ? 1 : 2;  
}  
char ch(int i) {  
   return i == 0 ? 'W' : i == 1 ? 'R' : 'G';  
}  
void solve() {  
   string s;  
   cin >> s;  
   int m = sz(s), n;  
   cin >> n;  
  
   vi cnt(3);  
   int k = 1;  
   while (k * 3 <= n) k *= 3;  
   vi a(m);  
   for (int i = 0; i < m; i++) a[i] = idx(s[i]);  
   while (n) {  
      int q = n / k;  
      while (q--) {  
         vi b = a;  
         for (int i = 0; i < m; i++) {  
            b[i] = (a[i] + a[md(m, i + k)]) % 3;  
         }  
         a = b;  
         n -= k;  
      }  
      k /= 3;  
   }  
   for (int i = 0; i < m; i++) cnt[a[i]]++;  
   for (int i: cnt) cout << i << ' ';  
   cout << endl;  
  
}

Tags:

Categories:

Updated:

Comments