题目链接:http://poj.org/problem?id=3276
枚举每次转向的牛数K 是O(n)
每次转向调整后面牛的状态O(n)
从头到尾转O(n)
总共O(n^3)
注意到第二个循环有一些冗余
拿这个来优化
用一个sum来记录区间(i - K ~ i - 1)转向了几次 即可在O(1)的时间内判断当前牛是否应该转向
sum的求法相当于求滑动定长区间和
#include <cstdio> #include <cstdlib> #include <ctime> #include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <stack> #include <set> #include <queue> #include <vector> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> P; const int maxn = 5100; int dir[maxn]; int f[maxn]; int n; int calc(int k) { memset(f, 0, sizeof(f)); int res = 0; int sum = 0; for(int i = 0; i < n - k + 1; i++) { if((dir[i] + sum) % 2 == 1) { res++; f[i] = 1; } sum += f[i]; if(i-k+1 >= 0) sum -= f[i-k+1]; } for(int i = n - k + 1; i < n; i++) { if((dir[i] + sum) % 2 == 1) return -1; if(i-k+1 >= 0) sum -= f[i-k+1]; } return res; } int main() { //freopen("in.txt", "r", stdin); scanf("%d", &n); char tmp[20]; for(int i = 0; i < n; i++) { scanf("%s", tmp); if(tmp[0] == 'F') dir[i] = 0; else dir[i] = 1; } int ans = n+1; int ans2; for(int k = 1; k <= n; k++) { int m = calc(k); if(m != -1 && m < ans) { ans = m; ans2 = k; } } printf("%d %d ", ans2, ans); return 0; }