pOJ 3276 Face The Right Way【思维 反转开关】

来源:互联网 发布:迅雷手游网络加速器 编辑:程序博客网 时间:2024/06/06 01:54

Face The Right Way
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 4300 Accepted: 1981

Description

Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing forward, like good cows. Some of them are facing backward, though, and he needs them all to face forward to make his life perfect.

Fortunately, FJ recently bought an automatic cow turning machine. Since he purchased the discount model, it must be irrevocably preset to turn K (1 ≤ K ≤ N) cows at once, and it can only turn cows that are all standing next to each other in line. Each time the machine is used, it reverses the facing direction of a contiguous group of K cows in the line (one cannot use it on fewer than K cows, e.g., at the either end of the line of cows). Each cow remains in the same *location* as before, but ends up facing the *opposite direction*. A cow that starts out facing forward will be turned backward by the machine and vice-versa.

Because FJ must pick a single, never-changing value of K, please help him determine the minimum value of K that minimizes the number of operations required by the machine to make all the cows face forward. Also determine M, the minimum number of machine operations required to get all the cows facing forward using that value of K.

Input

Line 1: A single integer: N 
Lines 2..N+1: Line i+1 contains a single character, F or B, indicating whether cow i is facing forward or backward.

Output

Line 1: Two space-separated integers: K and M

Sample Input

7

B

B

F

B

F

B

B

Sample Output

3 3

Hint

For K = 3, the machine must be operated three times: turn cows (1,2,3), (3,4,5), and finally (5,6,7)

Source

USACO 2007 March Gold

题目大意:N头牛排成了一列。每头牛或者向前或者向后,为了让所有的牛都面向前方,农夫约翰买了一台自动转向的机器,这个机器在购买的时候就必须设定一个数值K,机器每操作一次恰好使K头连续的牛转向。请求出为了让所有的牛都能面向前方需要最少的操作次数M和对应的最小值K。


思路:


1、首先考虑这样一点:交换区间翻转的顺序对结果是没有影响的,而且对应当前i号牛的头部朝向,是取决于这头牛被旋转了多少次决定的,那么问题我们可以将顺序抛开外不考虑,只考虑当前第i号牛被旋转了多少次。那么我们可以设定f【i】,表示区间【i,i+k-1】是否进行了翻转,如果进行了翻转,f【i】=1;否则f【i】=0;


2、那么我们再考虑解题的大方向:

①枚举一个值K,从1枚举到N,作为旋转区间的长度。

②如果第一头牛的朝向是B,那么明显我们要对第一头牛进行翻转,那么随之从第一头牛到第k头牛,也都会翻转过去。那么下一头牛是哪一个需要翻转呢?假设我们当前正在判断第i头牛,那么第i头牛的朝向应该是这样的:sum(f【i-k+1】~~f【i-1】)如果是奇数,并且当前牛原来朝向是F,那么这头牛是需要翻转的,同理如果是偶数,并且当前牛原来朝向是B,那么这头牛也是需要翻转的,如果这头牛需要翻转,那么对应设定f【i】=1;

③那么问题其实就是从前向后扫,如果遇到了需要翻转的牛,我们就将其翻转到正确的方向。

④但是还要考虑这样一种情况:最后几头牛如果需要翻转,但是从这头牛开始到最后一头牛的总数达不到K个,那么当前情况就是得不到解的情况(无论翻转多少次都不行)。


3、那么如果我们按照上述过程求解,时间复杂度会达到O(n^3),如果求和的那部分使用线段树/树状数组来优化,也是O(n^2logn),看起来还是很玄乎。其实我们再考虑这样一个点,就能使得时间复杂度降低到O(n^2):

sum(f【i+1-k+1】~~f【i+1-1】)=sum(f【i-k+1】~~f【i-1】)+f【i】-f【i-k+1】;

那么我们维护一个变量sum即可、


4、思路构建的差不多了之后,剩下的内容就是实现代码的过程了。


Ac代码:

#include<stdio.h>#include<string.h>using namespace std;char a[50000];int f[50000];int main(){    int n;    while(~scanf("%d",&n))    {        memset(f,0,sizeof(f));        memset(a,'\0',sizeof(a));        for(int i=1;i<=n;i++)        {            getchar();            scanf("%c",&a[i]);        }        int ans=0x3f3f3f3f;        int kk;        for(int k=1;k<=n;k++)        {            memset(f,0,sizeof(f));            int sum=0;            for(int i=1;i<=n-k+1;i++)            {                if(a[i]=='B')                {                    if(sum%2==0)                    {                        f[i]=1;                        sum++;                    }                    else                    {                        f[i]=0;                    }                }                if(a[i]=='F')                {                    if(sum%2==0)                    {                        f[i]=0;                    }                    else                    {                        f[i]=1;                        sum++;                    }                }                if(i-k+1>=1)sum-=f[i-k+1];            }            int flag=0;            for(int i=n-k+2;i<=n;i++)            {                if(a[i]=='B'&&sum%2==0)flag=1;                else if(a[i]=='F'&&sum%2==1)flag=1;                if(i-k+1>=1)sum-=f[i-k+1];            }            if(flag==1)continue;            int cont=0;            for(int i=1;i<=n;i++)if(f[i]==1)cont++;            if(cont<ans)            {                ans=cont;                kk=k;            }        }        printf("%d %d\n",kk,ans);    }    return 0;}



0 0
原创粉丝点击