티스토리 뷰

[Codeforces 1084C] The Fair Nut and String


난이도 1500짜리라서 얕봤다가 호되게 당한 문제이다. 처음에 버추얼로 돌 때는 10분만에 솔루션은 나왔는데 그것과 관련된 개념을 잘 몰라서 못 풀었다. 일단 결론부터 얘기하자면 이 문제는 b를 기준으로 분할했을 때, 연속해서 등장하는 a의 개수들이 있을텐데 그 개수로 집합의 원소로 구성해서 그 집합의 모든 부분집합의 곱들의 합이 곧 답이다. 예를 들어 설명하자면 " abaabaaa " 라는 문자열이 있다면 b를 기준으로 a의 개수를 {1,2,3}이 된다. 그래서 {1,2,3}으로 만들 수 있는 부분집합들의 원소들의 곱들의 합(=23)이 답이 된다. 이 연산을 단 O(N)만에 수행하는 공식이 존재하는데 나는 몰라서 naive하게 2^N 풀이밖에 몰랐다. 그래서 구글링해서 검색해본 결과 "Sum of products of all possible subsets"이라고 검색하니 나오더라. 그래서 단 O(N)만에 계산하는 공식은 다음과 같다. 

집합의 원소를 {a1,a2....a_n}이라고 할 때, Sum = (1+a1)(1+a2)....(1+a_n) - 1

간단하게 증명을 하자면 dp의 개념을 사용해야 한다.

만약 현재 i번 째까지의 원소의 곱들의 합을 dp[i]라 하고, 다음 (i+1)번 째를 구한다고 하자. (i+1)번 째 원소를 val[i+1]이라고 한다면 dp[i+1]은 다음 두 경우의 합과 같다.

  ① 기존의 구한 합(=dp[i])       ②val[i+1]번 째를 추가함으로써 새롭게 추가된 합(=dp[i]×val[i+1])

따라서 이를 정리하면 dp[i+1] = dp[i]×( 1 + val[i+1] )이 된다. 이를 n번 째 원소까지 똑같이 적용하면 위의 식처럼 된다. 그리고 마지막에 1을 빼는 것은 (1+ ~)의 형태에서 ' 1+' 처리하기 위함이다. 마지막에 1이 남는 것은 dummy라고 생각하면 된다.  


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
#include<stdio.h>
#include<vector>
using namespace std;
#define SIZE 100009
const int MOD=(1e9+7);
char str[SIZE];
int main(){
    scanf("%s",str+1);
    vector<int> v;
 
    for(int i=1,cnt=0 ; str[i] ; i++){
        if(str[i]=='a'){
            cnt++;
        }
        if(str[i]=='b' || str[i+1]==0 ){
            if(cnt) v.push_back(cnt);
            cnt=0;
        }
    }
 
    long long ans=1;
    for(int i=0 ; i<v.size() ; i++){
        ans=ans*(1+v[i]) % MOD;
    }
    ans--;
    printf("%lld\n",ans);
    return 0;
}
cs


'Problem Solving > Dynamic Programming' 카테고리의 다른 글

[Codeforces 1096D] Easy Problem  (0) 2019.04.21
[Codeforces 1113C] Sasha and a Bit of Relax  (0) 2019.03.10
[BOJ 2618] 경찰차  (0) 2019.01.29
[BOJ 11062] 카드 게임  (0) 2019.01.29
[BOJ 1695] 팰린드롬 만들기  (0) 2019.01.23
댓글