poj3276 Face The Right Way(反转问题,好题)

https://vjudge.net/problem/POJ-3276

首先意识到,对一个区间进行两次及以上的反转是没有意义的,而且反转次序不影响最终结果。

有点像二分搜索时用的逐个试的方法,每次翻的个数从1~n,然后进入函数判断。

由于正反性可以很巧妙地利用计数的奇偶来判断,所有这里优化复杂度,用f[i]记录i~i+k-1是否翻转了,不断向右判断,如果是反面就反转接下来的一组,直至最后,最后剩的几个如果全正就说明可以,如果有反面就说明不行。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<map>
 8 #define lson l, m, rt<<1
 9 #define rson m+1, r, rt<<1|1
10 #define INF 0x3f3f3f3f
11 typedef unsigned long long ll;
12 using namespace std;
13 int n, a[5010], f[5010];//f是i~i+k-1的是否翻了 
14 char c;
15 int calc(int k)
16 {
17     memset(f, 0, sizeof(f));//每一次都要初始化f 
18     int sum=0, res=0;
19     for(int i = 0; i <= n-k; i++){
20         if(!((a[i]+sum)&1)){//判断该点是反,需要翻转 
21             f[i] = 1;
22             res++;
23         }
24         sum += f[i]; 
25         if(i-k+1>=0)
26             sum -= f[i-k+1];
27     }
28     for(int i = n-k+1; i < n; i++){
29         if(!((a[i]+sum)&1)){
30             return -1;
31         }
32         if(i-k+1>=0)
33             sum -= f[i-k+1];
34     }
35     return res;
36 }
37 int main()
38 {
39     cin >> n;
40     for(int i = 0; i < n; i++){
41         cin >> c;
42         if(c == 'B') a[i] = 0;
43         else a[i] = 1;
44     }
45     memset(f, 0, sizeof(f));
46     int mini = INF, ans=-1;
47     for(int i = 1; i <= n; i++){
48         int num = calc(i);
49         //cout << i << " " << num << endl;
50         if(num>0&&num<mini){
51             mini = num;
52             ans = i;
53         }
54     }
55     cout << ans << " " << mini << endl;
56     return 0;
57 }
原文地址:https://www.cnblogs.com/Surprisezang/p/9043597.html