【NOI2006】 千年虫
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
千年虫是远古时代的生物,时隔几千万年,千年虫早已从地球上销声匿迹, 人们对其知之甚少。考古生物学家最近开始对其有了兴趣, 因为一批珍贵的千年虫化石被发现,这些化石保留了千年虫近乎完整的形态。 理论科学家们根据这些化石归纳出了千年虫的一般形态特征模型, 并且据此判定出千年虫就是蜈蚣的祖先!但科学家J发现了实际与理论 的一些出入,他仔细的研究了上百个千年虫化石,发现其中大部分千年虫的 形态都不完全符合理论模型,这到底是什么因素造成的呢?理论科学家K敏 锐的指出,千年虫的形态保存在化石中很有可能发生各种变化,即便最细 微的变化也能导致它不符合模型。于是,摆在科学家面前的新问题诞生了: 判断一个化石中的千年虫与理论模型的差距有多大? 具体来说,就是根据一个千年虫化石的形态A,找到一个符合理论模型的形态B,使 得B是最有可能在形成化石时变成形态A。 理论学家提出的“千年虫形态特征模型”如下(如上图所示):躯体由头、尾、躯干、足四大部分构成。 1.头,尾用一对平行线段表示。称平行于头、尾的方向为x方向;垂直于x的方向为y方向; 2.在头尾之间有两条互不相交的折线段相连,他们与头、尾两条线段一起围成的区域称为躯干,两条折线段都满足以下条件:拐角均为钝角或者平角,且包含奇数条线段,从上往下数的奇数条垂直于x方向。 3.每条折线段从上往下数的第偶数条线段的躯干的另一侧长出一条足,即一个上、下底平行于x方向的梯形或矩形,且其中远离躯干一侧的边垂直于x方向。 注意:足不能退化成三角形(即底边的长度均大于零),躯干两侧足的数目可以不一样。 (如下图,左边有4条足,右边有5条足) 可见,x-y直角坐标系内,躯干和所有足组成的实心区域的边界均平行或垂直于坐标轴。 为了方便,我们假设所有这些边界的长度均为正整数。因此可以认为每个千年虫的躯体都由一些单位方格拼成。每个单位方格都由坐标(x,y)唯一确定。 设头尾之间的距离为n,则我们可以用2×n个整数来描述一条千年虫B(如右图):将B沿平行x轴方向剖分成n条宽度为1的横条,每个横条最左边一格的x坐标设为Li,最右一格的的x坐标设为Ri。则(n,L1,L2,..,Ln,R1,R2,..Rn)就确定了一条千年虫。 由于岁月的侵蚀,在实际发现的化石中,千年虫的形状并不满足上面理论模型的规则,一些格子中的躯体已经被某些矿物质溶解腐蚀了。地质、物理、生物学家共同研究得出: 1、腐蚀是以格子为单位的,只能一整格被腐蚀; 2、腐蚀是分步进行的,每一步只有一格被腐蚀; 3、如果去掉一个格子后躯体不连通了,那么这个格子当前不会被腐蚀; 4、如果一个格子的左边邻格和右边邻格都还没被腐蚀,那么这个格子当前不会被腐蚀; 5、与头相邻的格子不能全部被腐蚀,与尾相邻的格子不能全部被腐蚀;倘若满足上面五条,我们仍然可以用(n,L’1,L’2,..,L’n,R’1,R’2,..R’n)来描述一个化石里头的千年虫的形态。其中L’i≤R’i。 例如下图: 现在你的任务是,输入一个化石里的千年虫的描述A,找一个满足理论模型的千年虫的描述B,使得B可以通过腐蚀过程得以变为A,且由B转化为A的代价(须被腐蚀的格子数)最少。输出此最小代价。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 *Problem: NOI2006 千年虫 3 *Author : Chen Yang 4 *Time : 2012.5.31 8:00 pm 5 *State : 40分 6 *Memo : dp、维数优化 7 */ 8 #include <cstdio> 9 #include <cstdlib> 10 #include <cstring> 11 #include <string> 12 #include <algorithm> 13 using namespace std; 14 const int maxn = 100010, inf = 1000000000; 15 int n, ans, l[maxn], now[maxn], f[2][maxn][2], best0[maxn]; 16 17 void work() 18 { 19 memset(f, 0x7f, sizeof f); 20 memset(best0, 0x7f, sizeof best0); 21 int Max = 0; 22 for (int i=1; i<n+1; ++i) Max = max(Max, now[i]); Max++; 23 for (int i=0; i<=Max-now[1]; ++i) f[1][now[1]+i][0] = i; 24 int ths = 1, pst = 0; 25 for (int i=2; i<n+1; ++i) 26 { 27 ths ^= 1; pst ^= 1; 28 if (i>2) for (int j=now[i-2]; j<Max+1; ++j) f[ths][j][0] = f[ths][j][1] = inf; 29 int best1 = inf; 30 for (int j=now[i-1]; j<now[i]; ++j) best1 = min(best1, f[pst][j][0]); 31 for (int j=Max; j>now[i]; --j) best0[j] = min(f[pst][j][1],best0[j+1]); 32 for (int j=now[i]; j<Max+1; ++j) 33 { 34 if (j-1>=now[i-1]) best1 = min(best1, f[pst][j-1][0]); 35 f[ths][j][1] = min(f[pst][j][1], best1); 36 f[ths][j][0] = min(f[pst][j][0], best0[j+1]); 37 f[ths][j][1] += j-now[i]; f[ths][j][0] += j-now[i]; 38 } 39 } 40 int Min = inf; 41 for (int i=now[n]; i<Max+1; ++i) Min = min(Min, f[ths][i][0]); 42 ans += Min; 43 } 44 45 int main() 46 { 47 freopen("worm.in", "r", stdin); 48 freopen("worm.out", "w", stdout); 49 scanf("%d", &n); 50 for (int i=1; i<n+1; ++i) scanf("%d%d", l+i, now+i); 51 work(); 52 for (int i=1; i<n+1; ++i) now[i] = maxn-l[i]; 53 work(); 54 printf("%d", ans); 55 return 0; 56 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 *Problem: NOI2006 千年虫 3 *Author : Chen Yang 4 *Time : 2012.5.31 10:00 pm 5 *State : Solved 6 *Memo : DP、维数优化、范围优化 7 */ 8 #include <cstdio> 9 #include <cstdlib> 10 #include <cstring> 11 #include <string> 12 #include <algorithm> 13 using namespace std; 14 const int maxn = 400010, inf = 100000000; 15 int n, ans, l[maxn], now[maxn], p[2], f[2][20][2], q[2][maxn]; 16 17 inline int getint() 18 { 19 int res = 0; char tmp; 20 while (!isdigit(tmp = getchar())); 21 do res = (res << 3) + (res << 1) + tmp - '0'; 22 while (isdigit(tmp = getchar())); 23 return res; 24 } 25 26 void work() 27 { 28 memset(f, 0x7, sizeof f); p[1] = 0; 29 for (int j=1; j<4; ++j) 30 for (int k=now[j]; k<now[j]+3; ++k) if (k>=now[1]) q[1][++p[1]] = k; 31 for (int i=1; i<=p[1]; ++i) f[1][i][0] = q[1][i] - now[1]; 32 int ths = 1, pst = 0; 33 for (int i=2; i<n+1; ++i) 34 { 35 ths ^= 1; pst ^= 1, p[ths] = 0; 36 int a = i-2<1? 1:i-2, b = n<i+2? n:i+2; 37 for (int j=a; j<b+1; ++j) 38 for (int k=now[j]; k<now[j]+3; ++k) if (k>=now[i]) q[ths][++p[ths]] = k; 39 for (int j=1; j<p[ths]+1; ++j) 40 { 41 f[ths][j][1] = inf, f[ths][j][0] = inf; 42 for (int k=1; k<p[pst]+1; ++k) 43 { 44 //printf("%d %d\n", f[pst][k][0],f[pst][k][1]); 45 if (q[pst][k]>q[ths][j]) f[ths][j][0] = min(f[ths][j][0], f[pst][k][1]); else 46 if (q[pst][k]<q[ths][j]) f[ths][j][1] = min(f[ths][j][1], f[pst][k][0]); else 47 f[ths][j][0] = min(f[ths][j][0], f[pst][k][0]), 48 f[ths][j][1] = min(f[ths][j][1], f[pst][k][1]); 49 } 50 f[ths][j][0] += q[ths][j]-now[i], f[ths][j][1] += q[ths][j]-now[i]; 51 //printf("%d %d\n", f[ths][j][0],f[ths][j][1]); 52 } 53 } 54 int Min = inf; 55 for (int i=1; i<p[ths]+1; ++i) Min = min(Min, f[ths][i][0]); 56 ans += Min; 57 } 58 59 int main() 60 { 61 freopen("worm.in", "r", stdin); 62 freopen("worm.out", "w", stdout); 63 n = getint(); 64 for (int i=1; i<n+1; ++i) l[i] = getint(), now[i] = getint(); 65 work(); 66 for (int i=1; i<n+1; ++i) now[i] = maxn-l[i]; 67 work(); 68 printf("%d", ans); 69 return 0; 70 }