POJ 3276 Face The Right Way 翻转(开关问题)

题目:Click here

题意:n头牛排成一列,F表示牛面朝前方,B表示面朝后方,每次转向K头连续的牛的朝向,求让所有的牛都能面向前方需要的最少的操作次数M和对应的最小的K。

分析:一个区间反转偶数次等于没反转,f[i]表示区间[i,i+K-1]是(1)否(0)进行了反转,所以在考虑第i头牛的时候,如果f[i-K+1]+f[i-K]+···+f[i-1]为奇数的话,这头牛的方向与起始的方向是相反的,否则方向没变。

 1 #include <cstdio>
 2 #include <cstring> 
 3 using namespace std;
 4 const int M = 5e3+3;
 5 int n;
 6 int dir[M];     // 牛的方向(0:F,1:B)
 7 int f[M];   // 区间[i,i-K+1]是否进行了反转
 8 
 9 void input()    {   
10     while( ~scanf("%d\n", &n ) )  {
11         for( int i=0; i<n; i++ )    {
12             char x;
13             scanf("%c\n", &x );
14             if( x == 'F' )  dir[i] = 0;
15             else    dir[i] = 1;
16         }
17     }
18 }
19 int calc( int k )   {   //  对于固定的K,求对应的最小的操作数,无解为-1
20     memset( f, 0, sizeof(f) );
21     int sum = 0;
22     int ret = 0;    // f的部分和
23     for( int i=0; i+k<=n; i++ ) {
24         if( (dir[i]+sum)%2 != 0 )   {   // 当前牛面朝后方
25             ret++;
26             f[i] = 1;
27         }
28         sum += f[i];
29         if( i-k+1 >= 0 )
30             sum -= f[i-k+1];
31     }
32     for( int i=n-k+1; i<n; i++ )   {    // 检查剩下的牛的朝向
33         if( (dir[i]+sum)%2 != 0 )
34             return -1;
35         if( i-k+1 >= 0 )
36             sum -= f[i-k+1];
37     }
38     return ret;
39 }
40 void solve()    {
41     int K = 1, M = n;
42     for( int i=1; i<=n; i++ )   {
43         int m = calc( i );
44         if( m < M && m >= 0 )  {
45             M = m;
46             K = i;
47         }
48     }
49     printf("%d %d\n", K, M );
50 }
51 int main()  {
52     input();
53     solve();
54     return 0;
55 }

 

posted @ 2015-08-12 14:58  TaoTaoCome  阅读(199)  评论(0编辑  收藏  举报