开关(反转问题)(挑程)

一开始没啥思路,然后往下看,发现是暴力的,但是暴力的非常有技巧。有两个很重要的点

(1)一个区间反转两次是不必要的,就是多余的(因此从头开始,找需要反转的区间,只过一遍就满足)

(2)最重要的是这个,每个区间反转的顺序是不影响最后结果的(所以可以从头开始。直到最后一个区间)

还有就是写的非常有技巧,用了一个类似移动窗口的东西,降低了一维的复杂度

ps:一定要注意边界。从1开始,区间为k,那么最后一个就是n-k+1;

x+k-1=n,所以x=n-k+1。这样好想一点。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <map>
 5 #include <set>
 6 #include <algorithm>
 7 #include <fstream>
 8 #include <cstdio>
 9 #include <cmath>
10 #include <stack>
11 #include <queue>
12 using namespace std;
13 const double Pi=3.14159265358979323846;
14 typedef long long ll;
15 const int MAXN=5000+5;
16 const ll mod=1e9+7;
17 
18 char b[MAXN];
19 int a[MAXN];
20 int f[MAXN];
21 int n;
22 int C(int k)
23 {
24     memset(f,0,sizeof(f));
25     int sum=0;int res=0;
26     for(int i=1;i<=n-k+1;i++)
27     {
28         if((a[i]+sum)%2==1)
29         {
30             res++;
31             f[i]=1;
32         }
33         sum+=f[i];
34         if(i-k+1>=1)
35             sum-=f[i-k+1];
36         //这个sum用的也是类似尺取法,真的好巧妙 
37     }
38     //之后检查剩下的牛,如果还是有向后的,那么就是无解
39     for(int i=n-k+2;i<=n;i++)
40     {
41         if((sum+a[i])%2==1)
42         {
43             return -1;
44         }
45         if(i-k+1>=1)
46             sum-=f[i-k+1];
47     } 
48     return res;
49 }
50 
51 int main(){
52     
53     scanf("%d",&n);
54     int minn=n+1; int K=1;
55     
56     for(int i=1;i<=n;i++)
57     {
58         cin>>b[i];
59         if(b[i]=='B')
60             a[i]=1;
61         else a[i]=0;
62     }
63     for(int k=1;k<=n;k++)
64     {
65         int m=C(k);
66         if(m>0&&minn>m)
67         {
68             minn=m;
69             K=k;
70         }
71     }
72     
73     printf("%d %d\n",K,minn);
74     return 0;
75 } 

 

posted @ 2019-02-25 15:47  Chuhanjing  阅读(288)  评论(0编辑  收藏  举报