您的位置:首页 > 其它

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

2016-04-16 00:30 579 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: