• P2882 Face The Right Way


    这道题没有一个比较详细的题解,我来提供一份。
    首先我们可以知道,反转区间的顺序对结果没有影响,而且一个区间如果翻转两次以上是没有意义的,所以,问题就变成了求哪些区间需要反转。
    我们枚举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;
    }
    

    如果有问题,可以私信。

  • 相关阅读:
    面试题26:复杂链表的复制
    面试题25:二叉树中和为某一值的路径
    面试题24:二叉搜索树后序遍历
    面试题23:二叉树层序遍历
    面试题22:栈的压入,弹出序列
    面试题21:包含min函数的栈
    面试题20:顺时针打印矩阵
    面试题19:二叉树镜像
    plugin.go 源码阅读
    server.go 源码阅读
  • 原文地址:https://www.cnblogs.com/gengchen/p/6037925.html
Copyright © 2020-2023  润新知