Face The Right Way [POJ3276] [开关问题]

题意:

有n头奶牛排成一排,有的朝前(F)有的朝后(B),现在你可以使k头奶牛一次性翻转朝向(n>=k>=1),问你最少的翻转次数和此时对应的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

Analysis

我们先来观察,可以发现,处理好i前面的点后,如果i这个点是B的话,就必须反向,而反向一次以上的话,是无效的(奇数次与1次等效,偶数次于0次等效)。

所以我们可以枚举K,然后从1处理到N,如果需要处理,就再套一个循环修改。这样的复杂度是O(N3),仍然不够。

我们想,如果这个数加上[i-k+1,i-1]的翻转次数,是奇数的话就代表需要切换,然后记录下区间次数和sum每次加上新处理的点,去掉即将在区间外的点。这样,就降到N2

Code

 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<cmath>
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<iostream>
 9 #include<algorithm>
10 #define RG register int
11 #define rep(i,a,b)    for(RG i=a;i<=b;++i)
12 #define per(i,a,b)    for(RG i=a;i>=b;--i)
13 #define ll long long
14 #define inf (1<<29)
15 #define maxn 5005
16 using namespace std;
17 int n,ans1=inf,ans2;
18 int num[maxn],f[maxn];
19 char s[5];
20 inline int read()
21 {
22     int x=0,f=1;char c=getchar();
23     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
24     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
25     return x*f;
26 }
27 
28 int main()
29 {
30     n=read();
31     rep(i,1,n)    {scanf("%s",s);if(s[0]=='B')    num[i]=1;}
32     rep(k,1,n)
33     {    
34         int sum=0,cnt=0;memset(f,0,sizeof(f));
35         for(RG i=1,lim=n-k+1;i<=lim;++i)
36         {
37             if((num[i]+sum)&1)    f[i]=1,cnt++;
38             sum+=f[i];if(i-k>=0)sum-=f[i-k+1];
39         }
40         rep(i,n-k+2,n)
41         {
42             if((num[i]+sum)&1)    
43             {
44                 cnt=-1;break;
45             }
46             sum+=f[i];if(i-k>=0)sum-=f[i-k+1];
47         }
48         if(cnt==-1)        continue;
49         if(cnt<ans1)    ans1=cnt,ans2=k;
50     }
51     cout<<ans2<<" "<<ans1;
52     return 0;
53 }
View Code
posted @ 2018-07-10 17:34  iBilllee  阅读(156)  评论(0编辑  收藏  举报