原题
题目分析
由题意可以知道,对于特定的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 }