POJ 3276 [Face The Right Way] 题解

题目大意

n头牛排成一行,有的牛面朝前,有的牛面朝后,每一次操作可以使连续的K头牛改变方向;求一个K,使得操作次数最少。输出K以及最少的操作次数。当有多个K满足条件时,输出最小的K。

题目分析

对一个区间来说,多次进行反转操作是没有意义的;另外反转的顺序对结果是没有影响的。所以这道题只需要对所有的可操作区间(即长度为K的区间)考虑是否需要反转。

考虑最左边的牛,当它面朝前时无需反转,当它面朝后时,就反转[1, K]区间一次。然后继续考虑第二头牛即可。

反转的时候不必每头牛都操作一次,只需用一个turns来记录当前区间的反转次数,考虑的下一头牛的状态就由它本身状态+turns的值来决定。随着区间往右移动,我们用区间左右更改的地方来更新turns即可。复杂度为O(n ^ 2)

source code

1234567891011121314151617181920212223242526272829303132333435363738
#include <cstring>const int maxn = 5500;const int INF = 100243535;int a[maxn], f[maxn], cnt[maxn];int () {    int n;    scanf("%d", &n);    for (int i = 0; i < n; i++) {        char s[10];        scanf("%s", s);        a[i] = (s[0] == 'F' ? 0 : 1);    }    for (int k = 1; k <= n; k++) {        memset(f, 0, sizeof(f));        int turns = 0;        for (int i = 0; i < n; i++) {

            if ((a[i] + turns) % 2 == 1) {                if (i + k > n) {                    cnt[k] = INF;                    break;                }                f[i] = 1;                cnt[k]++;                turns++;            }            if (i - k + 1 >= 0) turns -= f[i - k + 1];

        }       }    int ansK = 1;

    for (int k = 2; k <= n; k++) if (cnt[k] < cnt[ansK]) ansK = k;

    printf("%d %dn", ansK, cnt[ansK]);

}

原文:大专栏  POJ 3276 [Face The Right Way] 题解

原文地址:https://www.cnblogs.com/petewell/p/11615191.html

时间: 2024-10-09 09:12:19

POJ 3276 [Face The Right Way] 题解的相关文章

反转(开关问题) POJ 3276

POJ 3276 题意:n头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全部面朝前方.问:求最小操作m,再此基础上求k. 题解:1.5000头牛不是小数目,再怎么也得要n^2的算法,其中,枚举k是需要的,这就有n了,只能想办法给出一个n在O(n)时间内求出最小次数了. 2.对于给定的k,要想O(n)内把次数算出来,即只能扫一遍,一想到的必定是从前往后扫,遇到面朝后的就转头,但这一转牵扯太多,要改太多东西,k一大直接崩溃. 3.对于每次扫描

POJ 2406 Power Strings KMP运用题解

本题是计算一个字符串能完整分成多少一模一样的子字符串. 原来是使用KMP的next数组计算出来的,一直都觉得是可以利用next数组的,但是自己想了很久没能这么简洁地总结出来,也只能查查他人代码才恍然大悟,原来可以这么简单地区求一个周期字符串的最小周期的. 有某些大牛建议说不应该参考代码或者解题报告,但是这些大牛却没有给出更加有效的学习方法,比如不懂KMP,难倒不应该去看?要自己想出KMP来吗?我看不太可能有哪位大牛可以直接自己"重新创造出KMP"来吧. 好吧,不说"创造KMP

POJ 1088 滑雪 记忆化优化题解

本题有人写是DP,不过和DP还是有点差别的,应该主要是记忆化 Momoization 算法. 思路就是递归,然后在递归的过程把计算的结果记录起来,以便后面使用. 很经典的搜索题目,这种方法很多题目考到的. 关键还是如何把代码写清晰工整了,O(∩_∩)O~. #include <stdio.h> const int MAX_N = 101; int R, C; int arr[MAX_N][MAX_N]; int tbl[MAX_N][MAX_N]; inline int max(int a,

POJ 3714 Raid 最近对点题解

本题是一般最近对点求解,稍微增加点限定:有两个集合点,要求不同集合中的点的最近对. 那么就增加一个判断,如果是同一个集合中的点,那么就返回最大值,其他和一般的最近对点解法一样. 注意:本题数据有重合点,那么就要防止分类的时候溢出. Geeks上的最近对的程序是无法处理有重合点的情况的. #include <stdio.h> #include <stdlib.h> #include <float.h> #include <math.h> #include &l

POJ 2407 Relatives 欧拉函数题解

最基本的欧拉函数: 欧拉函数:求小于n的与n互质的个数 欧兰函数公式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)-..(1-1/pn),其中p1, p2--pn为x的所有质因数 就是要求这样的式子啦,不过求这条式子,相信有很多种方法可以求,这个不是难题: 不过问题是如何巧妙地求,如何简洁地写出代码. 直接硬求,或者求出质因数之后求都不是巧妙的方法了,参考了下别人的代码才知道可以写的这么巧妙的. 下面程序可以说是连消带打地求式子结果,分解质因子,可以如此简明地把解

POJ 1330 Nearest Common Ancestors LCA题解

本题是一个多叉树,然后求两点的最近公共单亲节点. 就是典型的LCA问题.这是一个很多解法的,而且被研究的很透彻的问题. 原始的解法:从根节点往下搜索,若果搜索到两个节点分别在一个节点的两边,那么这个点就是最近公共单亲节点了. Trajan离线算法:首次找到两个节点的时候,如果记录了他们的最低单亲节点,那么答案就是这个最低的单亲节点了. 问题是如何有效记录这个最低单亲节点,并有效根据遍历的情况更新,这就是利用Union Find(并查集)记录已经找到的节点,并及时更新最新访问的节点的当前最低单亲节

POJ 2823 Sliding Window 单调队列题解

本题是单调队列题解的入门,当然也可以使用RMQ 和 线段树,不过速度都没有单调队列那么快. 单调队列难点: 1 如何入列,保存数据 -- 最小单调队列的时候, 所有数都入列一次,在新的数据准备入列的时候,增加判断,如果当前数值小于队尾数值,那么队尾数值就出列.空队列的时候直接入列. 2 保存的数列是什么样的? 举例吧: 1 3 -1 -3 5 3 6 7 构建最小单调队列 第一个数值1的时候,空队列,那么入列,得到: 1 第二个数值3, 因为大于1:那么1不用出列,直接入列,得到: 1 3 第三

POJ 1470 Closest Common Ancestors LCA题解

本题也是找LCA的题目,不过要求多次查询,一般的暴力查询就必然超时了,故此必须使用更高级的方法,这里使用Tarjan算法. 本题处理Tarjan算法,似乎输入处理也挺麻烦的. 注意: 因为查询的数据会极大,故此使用一个数组记录所有查询数据就会超时的.我就载在这里了.查了好久才想到这点.因为我使用了一个vector容器记录了查询数据,故此每次都循环这组这么大的数据,就超时了.----解决办法:使用一个vector<int> quest来记录查询数组,这样每次都只需要循环某节点的邻接查询点就可以了

POJ 1050 To the Max DP题解

一维最大字段和的扩展. 要诀是固定列的左右点,比如左边记录为left, 右边记录为right,那么一个循环left从0到COL,行最大值,那么right从left开始循环到COl,就可以考虑到所有列组合了,这个循环是O(n*n),然后求范围列内的行最大子段和,时间是O(n), 这样巧妙地把二维的问题转化为一维了,最终时间复杂度是O(n^3). 可以参考Geeks上的讲解,不过他的最大子段和代码写的挺挫的,我的代码会简洁很多,而且也考虑到了负值情况了. Geeks地址:http://www.gee