2 条题解
-
0
贪心,枚举,差分
因为同一个点翻转两次就与没有翻转的效果相同了,因此我们有一个贪心策略为:
从左到右对于出现的每一个B翻转一次从当前点开始的区间,就能保证是最优解。
样例的模拟:
如果当前翻转的区间长度为3
粗体表示当前下标
B B F B F B B
(B B F) B F B B
F F B B F B B
F F B B F B B
F F B B F B B
F F (B B F) B B
F F F F B B B
F F F F B B B
F F F F B B B
F F F F (B B B)
F F F F F F F
F F F F F F F
F F F F F F F
但是我们会发现这样是n^2的,再枚举长度,就变为了n^3.因此,需要对区间翻转差分一下,总时间复杂度就是n^2的了
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 10009; int n; bool A[maxn],B[maxn]; int main(){ scanf("%d",&n); char ch; for(int i=1;i<=n;++i){ cin>>ch;A[i]=ch=='B'?0:1; } int mincnt=0x7fffffff,anslen; for(int len=1;len<=n;++len){ memset(B,0,sizeof B); bool b=0,flag=1;int cnt=0;//flag记录当前长度是否有解 for(int i=1;i<=n;++i){//因为区间翻转只有状态0和1,所以用^代替+和- b^=B[i];//数组B为记录差分的数组 if(!(A[i]^b)){//若当前位置为0 if(i+len-1>n){flag=0;break;}//唯一的失败条件:一次翻转的长度大于剩余的长度 b^=1,B[i+len]^=1; ++cnt; } } if(flag){if(cnt<mincnt)mincnt=cnt,anslen=len;} }printf("%d %d\n",anslen, mincnt); } -
0
by hansang:
#include<bits/stdc++.h> using namespace std; const int N=5010; int a[N], b[N]; int main(){ int n; scanf("%d", &n); for(int i=1; i<=n; i++){ char s[5]; scanf("%s", s); if(s[0]=='B') a[i]=0; else a[i]=1; } int ans=1e9, res=1e9; for(int k=1; k<=n; k++){ memset(b, 0, sizeof(b)); bool flag=1;int m=0, sum=0; for(int i=1; i<=n; i++){ sum^=b[i]; if(!(a[i]^sum)){ if(i+k-1>n) {flag=0;break;} sum^=1; b[i+k]^=1; m++; } } if(flag && m<=res) res=m, ans=k; } printf("%d %d\n", ans, res); return 0; }
- 1
信息
- ID
- 2632
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 9
- 标签
- 递交数
- 9
- 已通过
- 4
- 上传者