알고리즘2012. 3. 7. 19:04
문제 C. 모자 쓴 아이들

푸는데 0.3초밖에 안 걸린다. 추가로  sum of bar()도 dp로 바꿔버릴 수 있다. 사실 dp 테이블에서 삼각형 모양만 필요하니까 역삼각형 모양에 누적값을 저장해두는 식으로 활용하면 된다. 물론 dp[2001][2002]로 바꿔줘야 하지만... 그런데 이 문제에서는 그렇게 고친다고 엄청나게 빨라지지는 않는다. 그러므로 코드가 깔끔한 버전을 여기에 올림.


 
#include <stdio.h>
#include <string.h>
#include <assert.h>

int dp[2001][2001];

void foo()
{
	for (int i = 0; i <= 2000; ++i) {
		for (int j = 0; j <= i; ++j) {
			if (j > i / 2) {
				dp[i][j] = dp[i][i - j];
			} else if (j == 0) {
				dp[i][j] = 1;
			} else {
				dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
				if (dp[i][j] >= 32749)
					dp[i][j] -= 32749;
			}
		}
	}
}

int bar(int i, int j)
{
	if (i < 0 || i > 2000) {
		fprintf(stderr, "ERR_bar: %d\n", i);
	}
	if (j >= 0 && j <= i)
		return dp[i][j];
	return 0;
}

int main(void)
{
	foo();
	int T_;
	scanf("%d", &T_);
	for (int i_ = 1; i_ <= T_; ++i_) {
		int B, W, k, i;
		scanf("%d %d %d %d", &B, &W, &k, &i);
		assert(k <= B + W);
		if (i > k) {
			fprintf(stderr, "ERR_INPUT: %d %d\n", i, k);
		}
		const int kk = (B + W) - k;
		int ans = bar(k - i, B - i + 1) // i는 흰색
			+ bar(k - i, W - i + 1); // i는 검은색
		if (ans > 32749)
			ans -= 32749;
		if (ans) {
			int mul = 0;
			for (int m = i - 1 - kk; m <= i - 1; ++m) {
				mul += bar(i - 1, m);
			}
			mul %= 32749;
			for (int m = 1; m <= i - 1; ++m) {
				int x = 0;
				for (int p = 0; p <= kk; ++p) {
					x += bar(m - 1, p);
				}
				x %= 32749;
				mul -= bar(i - m - 1, kk - m + 1) * x;
				mul %= 32749;
			}
			//fprintf(stderr, "mul: %d\n", mul);
			ans *= mul;
			ans %= 32749;
		}
		printf("Case #%d: %d\n", i_, ans);
	}
	return 0;
}



Posted by asdfzxcv