P4170 [CQOI2007]涂色 题解

博客园同步

原题链接

简要题意:

一开始你有一个长度为 n n 的无色串,每次可以对一个区间染上相同的颜色。问最少多少次可以形成目标串。

告诉你,这题的蓝是假的,太假了,数据也太弱了。

完全是个暴力选手乱碾标算用的,其实本题的时间复杂度完全可以做到 O ( n 3 ) O(n^3) .

第一眼看数据范围还以为是大力爆搜剪枝

f i , j f_{i,j} 表示 [ i , j ] [i,j] 区间形成目标串中 [ i , j ] [i,j] 的最少次数。

如果 s i = s j s_i = s_j ,说明我们可以有两种情况:

  1. 反正这俩相等,那么 f i , j = f i + 1 , j f_{i,j} = f_{i+1,j} .

  2. 不然呢就是 f i , j = f i , j 1 f_{i,j} = f_{i,j-1} .

即:

f i , j = min ( f i + 1 , j , f i , j 1 ) f_{i,j} = \min(f_{i+1,j} , f_{i,j-1})

即从区间两端往内减少 1 1 .

如果不相等,我们需要枚举中间数 k k ,即把区间一分两段。

f i , j = min ( f i , k + f k + 1 , j ) ( i k < j ) f_{i,j}=\min(f_{i,k} + f_{k+1,j}) (i \leq k < j)

当然为了满足无后效性,我们需要先枚举长度(即按照区间长度进行计算,而不是按照左右端点)

此时我们兴致勃勃的写了一个程序。

时间复杂度: O ( n 2 ) O(n^2) .

实际得分: 60 p t s 60pts .

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
 
int n,f[101][101];
string s;

int main(){
	cin>>s; int n=s.size(); 
	memset(f,0x3f,sizeof(f));
	for(int len=1;len<=n;len++)
	for(int i=1;i<=n-len+1;i++) { //左
		int j=i+len-1; //右
		if(len==1) f[i][j]=1; //长度为1
		else if(s[i]==s[j]) f[i][j]=min(f[i+1][j],f[i][j-1]);
			else for(int k=i;k<j;k++) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
	} printf("%d\n",f[1][n]);
	return 0;
}

为什么会 WA \text{WA} 呢?你也许不太明白。

那你就别明白了,背代码万岁

本人发现,洛谷上置于楼顶的几篇题解都是状态转移方程里好好的 s i = s j s_i = s_j ,然后到代码里就是 s i 1 = s j 1 s_{i-1} = s_{j-1} ,让人难以明白。这里特此说明!而且,如果有 s i = s j s_i = s_j 也大多是下标从 0 0 开始枚举的。

然后你测了一下样例!

color 1.in
AAAAA

color 1.out
1

color.out
2

???你不明白自己的程序为什么会输出 2 2 ???

然后你开始调试,输出所有区间的值,得到一个结果是:

1 1 1
1 2 1
1 3 1
1 4 1
1 5 2
2 2 1
2 3 1
2 4 1
2 5 2
3 3 1
3 4 1
3 5 2
4 4 1
4 5 2
5 5 1

为什么所有以 5 5 结尾的区间(除了元区间 [ 5 , 5 ] [5,5] ) 都有了错误的答案?

这就是因为,字符串下标从 0 0 开始 !!!

你访问 s 5 s_5 是一个空字符!

真是一个大坑啊

时间复杂度: O ( n 3 ) O(n^3) .

实际得分: 100 p t s 100pts .

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
 
int n,f[101][101];
string s;

int main(){
	cin>>s; int n=s.size(); 
	memset(f,0x3f,sizeof(f));
	for(int len=1;len<=n;len++)
	for(int i=1;i<=n-len+1;i++) {
		int j=i+len-1;
		if(len==1) f[i][j]=1;
		else if(s[i-1]==s[j-1]) f[i][j]=min(f[i+1][j],f[i][j-1]);
			else for(int k=i;k<j;k++) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
	} printf("%d\n",f[1][n]);
	return 0;
}

发布了27 篇原创文章 · 获赞 33 · 访问量 536

猜你喜欢

转载自blog.csdn.net/bifanwen/article/details/105253624