Thursday, April 11, 2013

SRM 576 : If only...

With anxiety-caused symptons getting worse than I ever imagined, I had some distractions during this SRM, but once I began to code the div1 576's solution, I could distract my brain and feel good for a while. Therapy by TopCoder sounds like a promising field of research for whoever wants to investigate how to reduce stress crisis in programmers.

Div1 576 : The one with sponges

You got up to 300 things that make s[i] drops fall per minute, they are all aligned in a horizontal line and with a distance of 1 between them. You want to place up to M sponges of length L bellow these things that drop, in a way that each sponge receives between A and B drops per minute. If we number drop things from 0 to n-1, then each sponge must be at a horizontal position (left-most border) that matches the position of a drop between 0 and n - L. You can place sponges below other sponges, the sponges above intercept the drops. Count the total number of ways. Two ways are considered the same if for each sponge Q in the first way, there exists a sponge P that absorbs exactly the same set of drops.

With n <= 300, the worst complexity we could have is O(n3), so we need to be clever. I had the most difficulty trying to interpret the main rule. Then it appears to be complicated to optimize...

Let us make an array good[i][j] if it is a good idea to have a sponge that absorbs the drops between i and j. (The total number of drops per minute is between A and B). We can see the problem as assigning sponges in a way that the drops they receive come from a good interval. Of course, doing such an assignment is not always possible.

The trick is to notice that for each set of contiguous intervals that were picked to have a sponge. The necessary and sufficient condition for it to have a solution (and a unique solution) is that at least one of the intervals is of size L.

With that in mind, it is simple to make a dynamic programming with three states: [x][M][state], where x is the number of positions that were already processed. state is 0, if the last position does not contain a sponge, 1 if the last position contains a sponge and such set of contiguous intervals does not ye contain a interval of length L, and 2 otherwise.

const int MOD = 1000000009;

struct TheExperiment
{
string s;

bool good[301][301];

int L;
int dp[301][301][3];

int mem(int x, int m, int didL)
{
int & res = dp[x][m][didL];
if (res == -1) {
if (x == s.size()) {
res = ( (didL != 1) && (m == 0) );
} else {
res = 0;
if (m > 0) {
for (int y = 1; (y <= L) && (x + y <= s.size()); y++) {
if (good[x][x + y]) {
int nd = didL;
if (y == L) {
nd = 2;
} else if ( didL == 0 && y != L ) {
nd = 1;
}
res += mem(x+y, m- 1, nd );
if (res >= MOD) res -= MOD;
}
}
}
if (didL != 1) {
res += mem(x + 1, m , 0 );
if (res >= MOD) res -= MOD;
}

}
}
return res;
}


int countPlacements(vector <string> intensity, int M, int L, int A, int B)
{
memset(dp, -1, sizeof(dp));
s = accumulate(intensity.begin(), intensity.end(), string(""));
this->L = L;

int acum[301];
acum[0] = 0;
for (int i=0; i<s.size(); i++) {
acum[i + 1] = acum[i] + s[i] - '0';
}
for (int i=0; i<=s.size(); i++) {
for (int j=i; j<=s.size(); j++) {
int total = acum[j] - acum[i];
good[i][j] = ( A <= total && total <= B);
}
}
return mem(0, M, 0);

}
};

I took long to think of the solution. But I was barely able to finish the code and pass examples before the 10 minutes mark. I was thrilled to find that I was going to have 10 minutes to solve div1 easy. Too bad it turned out to be the kind of problem that is complicated to implement. I could implement the code in 10 minutes, but it had mistakes.

I fear my div1 576 may have code mistakes, I am not performing at 100% :(.

No comments :