poj3276(反转/开关问题)

题目大意:

给你一个长度为n的字符串,包含字母F和B

你可以把区间k(一个常数)内的所有F变成B,B变成F。

为了把这个字符串都变成F,求变化的最小次数和其对应的k的值

分析:

《挑战程序设计竞赛》反转法的例题,(此做法非书上做法)

枚举k,对于每个k,

只要序列最左端的B变成F,然后依次变化,得到答案:

枚举起点然后把k个字母进行变化,这个揭发的时间复杂度是O(n^3),对于5000的数据,显然TLE

首先枚举k是肯定的,

对于每个k,把序列扫一遍得到答案,到达n^2,才可满足时间要求,所以要思考一下对于区间如何处理

考虑到反转区间后,区间内部不变的是相邻元素之间的关系,所以可以另t[n]表示该元素与前面的元素的关系,相同的话就用t[i]=0,否则t[i]=1,

对于区间[a,a+k-1],反转后变化的是t[a]和t[a+k]

所以对于一个t[i]=1,只需要改变t[i]和t[i+k]

这样就可以在O(n)的时间内对一个k求解

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<string>
 5 #include<queue>
 6 #include<vector>
 7 #include<set>
 8 #include<map>
 9 #include<algorithm>
10 
11 #define ll long long 
12 #define mem(a,b) memset(a,b,sizeof(a))
13 #define now t
14 const int maxn=6000;
15 int ini[maxn];
16 char data[maxn];
17 int t[maxn];
18 using namespace std;
19 int ans=9999999,K;
20 int main()
21 {
22     int n;scanf("%d",&n);
23     data[0]='F';
24     //scanf("%s",data+1);
25     for(int i=1;i<=n;i++)//预处理
26     {
29         cin>>data[i];
30         if(data[i]==data[i-1]) ini[i]=0;
31         else ini[i]=1;
32     }
33     for(int k=1;k<=n;k++)
34     {
35         memcpy(t,ini,sizeof(ini));
36         int cnt=0;
37         for(int i=1;i<=n-k+1;i++)
38         {
39             if(t[i]){cnt++;t[i+k]^=1;}//t[i]不会再用到了,不需要再改动了
40         }
41         for(int i=n-k+2;i<=n;i++)//后面这些元素不够一个区间k的数量
42         {
43             if(t[i]){cnt=999999;break;}
44         }
45         if(cnt<ans){ans=cnt;K=k;}
46     }
47     printf("%d %d\n",K,ans);
48 }

 

转载于:https://www.cnblogs.com/codeoosacm/p/10241708.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值