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
时间: 2024-11-09 09:57:28