POJ 1009は、解題レポートの解題レポートではない
久しぶりにpojの問題を書いたので、必ず続けなければなりません.結局、コードを書くことが生きているので、アルゴリズムの重要性は言うまでもありません.1009この問題はもう長い間悩んでいたが、実は問題は難しくなく、見た後の考えも直感的で、同じ数字が3行以上を越えたことを考慮すると、中間部分は計算しなくてもいいに違いない.以前はmapを作ることができると思っていましたが、中間値を含む9つの数からなる配列が以前に計算されていれば、mapのvalueを直接出力すればいいと思います.しかし、このように探すたびに、比較するたびに、効率はかえって低くなったようだ.また、入力したデータが多ければ、その個数の和がintの範囲を超える可能性があると考えて書いたので、いろいろ考えたようです.
この問題はやっと無理に「見る」ことができた.自分で何度やっても完成しなかったので、最後に大牛の解題報告を見ました.だから実は自分も書き終わっていません.ここでまとめて、向上してほしいです.
プログラムを書くときはフレームワークに従って書いて、まずいくつかの部分に分けることを考えてから、各部分の細部の内容を拡張します.この難しくない問題は、最初から細部に自信がありませんでした.
これは大牛のコードです.ここに少し注釈をつけた.ソースコードは、http://xay0.blog.163.com/blog/static/43925338200801202220646/
c++ code:
thestoryofsnow
1009
Accepted
228K
16MS
C++
4691B
この問題はやっと無理に「見る」ことができた.自分で何度やっても完成しなかったので、最後に大牛の解題報告を見ました.だから実は自分も書き終わっていません.ここでまとめて、向上してほしいです.
プログラムを書くときはフレームワークに従って書いて、まずいくつかの部分に分けることを考えてから、各部分の細部の内容を拡張します.この難しくない問題は、最初から細部に自信がありませんでした.
これは大牛のコードです.ここに少し注釈をつけた.ソースコードは、http://xay0.blog.163.com/blog/static/43925338200801202220646/
c++ code:
thestoryofsnow
1009
Accepted
228K
16MS
C++
4691B
#include <stdio.h>
#include <assert.h>
int n, t, k;
int num[2000], sum[2000], digit[2000], ansdigit[5000], ansnum[5000];
// , math
int abs(int x)
{
if (x < 0) return -x;
return x;
}
// i
/*****
*0 1 2
*3 4
*5 6 7
******/
inline int map(int c, int now)
{
switch (c)
{
case 0: return now - t - 1;
case 1: return now - t;
case 2: return now - t + 1;
case 3: return now - 1;
case 4: return now + 1;
case 5: return now + t - 1;
case 6: return now + t;
case 7: return now + t + 1;
}
assert(false);
return -1;
}
// y , forward , 0 , 1
int number(int c, int y, bool forward)
{
int i;
if (forward)
{
for (i = c; i <= n; ++i)
if (sum[i] >= y) break;
return i;
}
else
{
for (i = c; i > 0; --i)
if (sum[i] < y) break;
return i+1;
}
}
//
bool ok(int now, int i)
{
if (now < t && (i == 1 || i == 0 || i == 2)) return false;//
if (now > sum[n] - t && (i == 6 || i == 5 || i == 7)) return false;//
if (now % t == 1 && (i == 0 || i == 3 || i == 5)) return false;//
if (now % t == 0 && (i == 2 || i == 4 || i == 7)) return false;//
return true;
}
// 8
int get(int x, int now)
{
int i, max = 0, m;
for (i = 0; i < 8; ++i)
{
m = map(i, now);
if (ok(now, i) && m > 0 && m <= sum[n])
{
m = number(x, m, i / 4);
if (max < abs(digit[x] - digit[m])) max = abs(digit[x] - digit[m]);
}
}
return max;
}
//
int late(int x, int now, int r)
{
int p;
if (r <= now) return 1;
if (now % t != 1)
{
if (digit[number(x, now - 1, 0)] != digit[x]) return 1;
if (now > t)
{
p = number(x, now - t - 1, 0);
if ((sum[p] - 1) / t < (now - 1) / t)
{
if (sum[p] <= now - t + 1) return 1;
if (r > sum[p] - 1 + t) r = sum[p] - 1 + t;
}
}
if (now <= sum[n] - t)
{
p = number(x, now + t - 1, 1);
if ((sum[p] - 1) / t == (now - 1) / t + 1)
{
if (sum[p] <= now + t + 1) return 1;
if (r > sum[p] - 1 - t) r = sum[p] - 1 - t;
}
}
return r - now + 1;
}
else
{
if (now > t)
{
p = number(x, now - t, 0);
if ((sum[p] - 1) / t < (now - 1) / t)
{
if (sum[p] <= now - t + 1) return 1;
if (r > sum[p] - 1 + t) r = sum[p] - 1 + t;
}
}
if (now <= sum[n] - t)
{
p = number(x, now + t, 1);
if ((sum[p] - 1) / t == (now - 1) / t + 1)
{
if (sum[p] <= now + t + 1) return 1;
if (r > sum[p] - 1 - t) r = sum[p] - 1 - t;
}
}
return r - now + 1;
}
}
// , start end 。 , start end
void make(int x, int start, int end)
{
int i, r;
int a = (start - 1) / t, b = (end - 1) / t;
if (a != b)//
{
make(x, start, b * t);//
make(x, b * t + 1, end);//
return;
}
// get , last ,the 。 ,
int last = get(x, start), sum = 0, the;
for (i = start; i <= end;)
{
the = get(x, i);
r = late(x, i, end - 1);
if (the == last)
sum += r;//
else
{
ansdigit[++k] = last;
ansnum[k] = sum;
sum = r;
last = the;
}
i += r;
}
ansdigit[++k] = last;
ansnum[k] = sum;
}
int main()
{
int i, x, y;
sum[0] = 0;
while (scanf("%d", &t) && t)
{
i = 0;
k = 0;
while (scanf("%d%d", &x, &y) && (x || y))
{
digit[++i] = x; //digit
num[i] = y;//num
sum[i] = sum[i - 1] + num[i];//sum , i 8
}
n = i;
for (i = 1; i <= n; ++i)
{
if (num[i] <= t + t + 2)// 3
make(i, sum[i - 1] + 1, sum[i]);
else
{
make(i, sum[i - 1] + 1, sum[i - 1] + t + 1);// if
ansdigit[++k] = 0;// 0
ansnum[k] = num[i] - 2 * t - 2;//0
make(i, sum[i] - t, sum[i]);//
}
}
printf("%d
", t);//
for (i = 1; i <= k;)
{
int outdigit = ansdigit[i];
int outnum = 0;
while (i <= k && ansdigit[i] == outdigit)// ,
outnum += ansnum[i++];
printf("%d %d
", outdigit, outnum);
}
printf("0 0
");
}
printf("0
");
}