原题

题目链接

题目分析

由题意可以知道,对于特定的k,同一个区间反转两次是无意义的,考虑能翻第一头牛的区间只有第一个区间,因此第一头牛直接决定是否要翻转第一个区间,然后问题规模减1,同理再对第二头牛进行同样的分析.这里的翻转操作可以用前缀和优化,设f[i]=1表示以第i头牛开始的区间被翻过,f[i]=0则表示没被翻过,则考虑第j头牛时,只需统计前k-1头牛的f值,如果和是奇数则表明第j头牛的朝向与原方向相反,否则相同,最后就可以用O(N)的复杂求求解一个k的最小步骤m,由于所有k都要试一遍,最后复杂度会变成O(N).

代码

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <utility>
 6 #include <ctime>
 7 #include <cmath>
 8 #include <cstring>
 9 #include <string>
10 #include <stack>
11 #include <queue>
12 #include <vector>
13 #include <set>
14 #include <map>
15
16 using namespace std;
17 typedef unsigned long long ULL;
18 typedef long long LL;
19 typedef long double LB;
20 const int INF_INT=0x3f3f3f3f;
21 const LL INF_LL=0x3f3f3f3f3f3f3f3f;
22
23 int N;
24 char cow[5000];
25 bool f[5000];
26 int ans=INF_INT,res;
27
28 bool check(int k,int sum) //检查当区间长度为k时是否能把所有牛朝前放
29 {
30     for(int i=N-k+1;i<N;i++)
31     {
32         if((sum&1)&&cow[i]=='F') return false;
33         else if(!(sum&1)&&cow[i]=='B') return false;
34         if(i-k+1>=0) sum-=f[i-k+1];
35     }
36     return true;
37 }
38
39 int main()
40 {
41 //    freopen("testdata.in","r",stdin);
42 //  freopen("std.out","w",stdout);
43     cin>>N;
44     for(int i=0;i<N;i++)
45         cin>>cow[i];
46     for(int i=1;i<=N;i++)
47     {
48         int sum=0,cnt=0;
49         for(int j=0;j<=N-i;j++)
50         {
51             if(sum&1)
52             {
53                 if(cow[j]=='F') f[j]=1,cnt++;
54                 else f[j]=0;
55             }
56             else
57             {
58                 if(cow[j]=='B') f[j]=1,cnt++;
59                 else f[j]=0;
60             }
61             if(j-i+1>=0) sum-=f[j-i+1];
62             sum+=f[j];
63         }
64         if(check(i,sum)&&ans>cnt)
65             ans=cnt,res=i;
66
67     }
68     cout<<res<<' '<<ans<<endl;
69     return 0;
70 }
01-07 11:10