[POJ 3276] Face The Right Way (翻转问题+技巧)

来源:互联网 发布:网页设计排版软件 编辑:程序博客网 时间:2024/05/18 10:33

POJ - 3276
有 N个奶牛排成一列,有些朝前有些朝后,
一次可以翻转连续的 K头奶牛的朝向,K是固定的
求最少翻转次数,以及最小的 K

这种翻转的问题有两个很明显的性质
1) 翻转的位置先后是无关的
2) 同一个地方最多翻转一次

于是枚举 K,再枚举 N依次去翻转
K长度的窗口依次向右滑,如果此时最左边的牛朝后
则一定要翻转,因为此后的操作都与其无关了

不过直接搞的话时间复杂度是 O(n^3)
用到一点小技巧,就是用 rev标记此时是否要翻转
如果翻转,则 rev^=1,并用 note数组标记此次翻转退出的地点
这样时间就优化到了 O(n^2)

有个坑点:
由于我 i从 K开始,一直到 N
所以如果走到 N的时候,还需额外的一个循环判断 N-K+2..N 的是否能翻转完
不仅如此,剩下的翻转退出标记也要一一算到

#include <cstdio>#include <iostream>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <map>#include <set>#include <queue>using namespace std;typedef pair<int,int> Pii;typedef long long LL;typedef unsigned long long ULL;typedef double DBL;typedef long double LDBL;#define MST(a,b) memset(a,b,sizeof(a))#define CLR(a) MST(a,0)#define Pow2(a) (a*a)const int maxn=5e3+10;int N;bool inpt[maxn];bool note[maxn];int main(){    while(~scanf("%d", &N))    {        CLR(inpt);        for(int i=1; i<=N; i++)        {            char chr;            scanf(" %c", &chr);            if(chr=='B') inpt[i]=1;        }        int ansk=1,ans=N+10;        for(int K=1; K<=N; K++)        {            int cnt=0;            bool rev=0;            CLR(note);            for(int i=K; i<=N; i++)            {                bool now=inpt[i-K+1]^rev;                if(now)                {                    note[i]=1;                    cnt++;                    rev^=1;                }                rev^=note[i-K+1];            }            bool ok=1;            for(int i=N-K+2; i<=N; i++)            {                if(inpt[i]^rev){ok=0;break;}                rev^=note[i];            }            if(ok&&cnt<ans)            {                ansk=K;                ans=cnt;            }        }        printf("%d %d\n", ansk, ans);    }    return 0;}
0 0
原创粉丝点击