您的位置:首页 > 其它

P2882 Face The Right Way - USACO07MAR

2016-11-07 10:51 197 查看

这道题没有一个比较详细的题解,我来提供一份。
首先我们可以知道,反转区间的顺序对结果没有影响,而且一个区间如果翻转两次以上是没有意义的,所以,问题就变成了求哪些区间需要反转。
我们枚举k。对于每一个k,我们设计一个calc函数来判断k的操作次数。
显然的,我们可以设计出一种方法,就是每一次都检查最左端,然后进行反转,很容易写出下面的calc函数。

int calc(int k) {
int ans = 0;
int i;
for(i = 1; i + k - 1 <= N; i++) {
if(f[i] == 1) {
for(int j = i; j <= i + k - 1; j++) {
f[j] = !f[j];
}
ans++;
}
}
for(i--; i <= N; i++) {
if(f[i] == 1) return -1;
}
return ans;
}

这样的检查方式复杂度为O(n2),再结合枚举k,总的复杂度是O(n3),这样的复杂度可以通过70%的数据,但还不够好。
我们来考虑怎么优化。显然的,我们没有必要去记录每一个的状态,我们只需要存储每一个区间是否反转过。所以,我们定义
f[i]为区间[i, i+k-1]是否反转。
这样,反转的复杂度就降到了O(1),总的复杂度就降到了O(n2),这样我们就可以AC这道题了。
对于实现上还有一个问题,就是怎么判断每一个格子的状态,这个问题我们留给读者思考。
下面贴上calc的代码。

int calc(int K) {
memset(f, 0, sizeof(f));
int ans = 0;
int sum = 0;
for(int i = 0; i + K <= N; i++) {
if((g[i] + sum) % 2 != 0) {
ans++;
f[i] = 1;
}
sum += f[i];
if(i - K + 1 >= 0) sum-=f[i-K+1];
}
for(int i = N - K + 1; i < N; i++) {
if((g[i] + sum) % 2 != 0) {
return -1;
}
if(i-K+1 >= 0) {
sum-=f[i-K+1];
}
}
return ans;
}

如果有问题,可以私信。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: