反转问题,WA了无数次了,简直欲哭无泪。。技巧是求定长子段和,区间标记。构造定长前缀和函数来判断到第i头牛时该头牛的状态。优化后的代码如下:
/*Memory 144K Time 407MS*/
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int N;
const int MAXN = 5000;
bool dir[MAXN+1], f[MAXN+1];
int calc(int K){
memset(f, 0, sizeof(f));
int res = 0;
bool sumi = 0;
int i;
for(i=0; i+K-1<N; i++){
if((sumi+dir[i])%2 != 0){
res++;
f[i] = 1;
}
if(i-K+1 < 0) sumi = (sumi + f[i])%2;
else sumi = (sumi + f[i] - f[i-K+1] + 2)%2;
}
for( ; i<N; i++){
if((sumi+dir[i])%2 != 0){
return -1;
}
sumi = (sumi - f[i-K+1] + 2)%2;
}
return res;
}
void solve(){
int K = 1, M = N; //放缩
for(int k=1; k<=N; k++){
int m = calc(k);
if(m >= 0 && m < M){
M = m;
K = k;
}
}
printf("%d %d\n", K, M);
}
int main(){
while(scanf("%d", &N) != EOF){
char ch;
int cnt = 0;
while(cnt < N){
scanf("%c", &ch);
if(ch == 'F') dir[cnt++] = 0;
if(ch == 'B') dir[cnt++] = 1;
}
solve();
}
return 0;
}
如果把第一段分成两个for循环写也是可以过的:
for(i=0; i-K+1<0 && i+K-1<N; i++){ //必须加此边界,否则要跪,之前一直都没找出这个bug,WA了好多
if((sumi+dir[i])%2 != 0){
res++;
f[i] = 1;
}
sumi = (sumi+f[i])%2;
}
for( ; i+K-1<N; i++){
if((sumi+dir[i])%2 != 0){
res++;
f[i] = 1;
}
sumi = (sumi + f[i] - f[i-K+1] + 2)%2;
}
另外,再附上我找这个bug的测试程序
#include <cstdio>
#include <iostream>
using namespace std;
int N;
void f1(int K){
int i;
for(i=0; i-K+1<0; i++){
cout<<"a";
}
for( ; i+K-1<N; i++){
cout<<"b";
}
cout<<endl;
}
void f2(int K){
int i;
for(i=0; i+K-1<N; i++){
if(i-K+1 < 0) cout<<"a";
else cout<<"b";
}
cout<<endl;
}
int main(){
int K;
cin>>N>>K;
f1(K);
f2(K);
return 0;
}