BOJ 1416 - 팬 서비스
Solution 1Permalink
정도로 푸는 풀이로 먼저 통과했다.
를 번 째 수까지 채웠을 때 합이 이고 짝수 - 홀수 = 인 경우의 수라고 하자.
포함 배제의 원리로 1번 조건 만족 + 2번 조건 만족 - 1번, 2번 조건 모두 만족을 하는것이 정답이다.
각 와 각 에 대해 포함되는 모든 값을 미리 더해서 전처리해두면 세가지 모두 에 구할 수 있다.
공간복잡도를 위해 토글링을 해야한다.
const ll mod = 999983;
inline ll md(ll x) { return md(mod, x); }
template<class T>
inline void mds(T &a, T b) { a = md(a + b); }
template<class T>
inline void mdp(T &a, T b) { a = md(a * b); }
vi in;
int k;
// i 번째까지, 총합이 j이고, 짝수 - 홀수가 k인 것의 경우의 수
int dp[2][455][1000];
int sum_sum[455];
int sum_diff[1000];
const int o = 500;
void solve() {
cin >> k;
string s;
cin >> s;
for (char c: s) in.pb(c - '0');
sort(all(in));
dp[0][0][o] = 1;
for (int i = 1; i <= k; i++) {
int I = i % 2, J = I ^ 1;
memset(dp[I], 0, sizeof dp[I]);
for (int d: in) {
for (int sum = 0; sum <= 9 * i; sum++) {
for (int diff = -i * 9; diff <= i * 9; diff++) {
if (sum - d >= 0) {
int nxt = i % 2 == 1 ? diff + d : diff - d;
nxt += o;
if (nxt >= 0 && nxt < 1000)
mds(dp[I][sum][diff + o], dp[J][sum - d][nxt]);
}
}
}
}
}
ll ans_all = 0, ans1 = 0, ans2 = 0;
for (int sum = 0; sum <= k * 9; sum++) {
for (int diff = -k * 9; diff <= k * 9; diff++) {
mds(sum_sum[sum], dp[k & 1][sum][diff + o]);
mds(sum_diff[diff + o], dp[k & 1][sum][diff + o]);
}
}
for (int sum = 0; sum <= k * 9; sum++) {
for (int diff = -k * 9; diff <= k * 9; diff++) {
mds(ans1, 1ll * dp[k & 1][sum][diff + o] * sum_sum[sum]);
mds(ans2, 1ll * dp[k & 1][sum][diff + o] * sum_diff[diff + o]);
mds(ans_all, 1ll * dp[k & 1][sum][diff + o] * dp[k & 1][sum][diff + o]);
}
}
cout << md(ans1 + ans2 - ans_all);
}
Solution 2Permalink
조건을 좀 더 살펴보자.
가 짝수일 때 기준으로,
번 조건은 를 의미한다.
번 조건은 를 의미한다.
연립하면 이다. 또한 이로써 도 얻는다.
따라서 를 그냥 번째 수까지 채웠을 때 합이 가 되는 것이라고 해보자. 에 구할 수 있다.
번 조건의 경우의 수는 그냥 이다.
번 조건의 경우의 수도 따지고보면 번 조건의 경우의 수와 다를수 없다.
따라서 구한 값에 를 해주자.
번 조건의 경우의 수는 를 만드는 경우의 수이다.
의 기우성에 관계없이 와 를 곱한값을 번 조건의 경우의 수에 두배한 것에서 빼면 된다.
Comments