URAL-1830(Help in the RNOS)解题报告
首先先贴题目地址吧:http://acm.timus.ru/problem.aspx?space=1&num=1830。。。
今天A这题很不爽,wa了n次,而且还超时。原来是自己写的递归把自己搞糊涂了,哎,路途遥远,被水题虐了。
先讲题意:此题背景为帮助信息的查看,按F1打开帮助信息的第一页,每一页有两个按钮,一个是打开下一页,一个是关闭下一页。我们对这些页码从0~n-1进行编号,如果有很多页面是打开的,那么只能看到编号小的页面,1代表打开,0代表关闭;打个比如,有4个页面,1011,那么第0页,第2页和第3页是打开的,第1页是关闭的,所以我们只能看到第0页,看不到其它的,只有第0页能够通过F1来打开和关闭自己,其它的页面必须依赖上一页在操作,它给出两个字符串,第一个代表初始条件,页面的状态,第二便是你需要达到的状态,让你求操作的次数而且要求操作的次数最少。。。
对于它的样例:
3
111
000
正确操作是:111->011->010->110->100->000,所以总共5次,说到这里应该大家对题目都清晰了。
我们现在分析,对于字符串a和字符串b
如果a="101001"
b="100101"那么我们就不必要考虑后两位,只用考虑前4个页,也就是说我们从字符串的尾巴开始模拟,如果相等则不操作,不相等则操作;
PS:假如a[i]和b[i]不相等,那么我们要修改a[i]位,则我们需要把a[i-1]位变成1,a[i-1]前面的所有位全部变成0,这样才能只显示第i-1位,而且操作第i位!
我们使用一个递归函数solve(int i,char k),表示我们把第i位变成字符k,而且从0~i-1位全部变成0;但是直接递归必定TLE,因为时间复杂度将是o(2^n);
所以我们需要优化,不难看出如果将00000变成00001,则需要操作(2^5)-1次,如果这一点理解了,那么我们可以直接进入我们的代码,如果不理解,那么
请你耐心一点归纳一下,相信你的能力可以很快得出这个简单结论,这里就不过多解释:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //==================================================================== 2 //Name : 3 //Author :hxf 4 //copyright :http://www.cnblogs.com/Free-rein/ 5 //Description: 6 //Data :2012.8.18 7 //======================================================================== 8 #include<iostream> 9 #include<algorithm> 10 #include<stdio.h> 11 #include<math.h> 12 #include<string> 13 #include<cstring> 14 #include<vector> 15 #include<stack> 16 #include<queue> 17 #include<map> 18 #define MAXN 100050 19 #define inf 10100 20 using namespace std; 21 int n; 22 char str[55];//初始状态 23 char set[55];//结束状态 24 long long ans;//记录总的操作次数 25 void solve(int a,char k) 26 { 27 if(a==0)//递归函数的终止条件,这里不解释 28 { 29 if(str[a]!=k) 30 { 31 ans++; 32 str[a]=k; 33 } 34 return; 35 } 36 if(str[a]==k)//如果str[a]等于k,那么将str[a-1]变为0,因为solve(a-1,'0')已经代表a-1前面的位都是0 37 solve(a-1,'0'); 38 else//如果不等于 39 { 40 solve(a-1,'1');//讲str[a-1]变成1,才能修改str[a] 41 ans=ans+((long long)1<<a);//计数器加上2^a-1,然后加上修改str[a]的1次,正好2^a 42 } 43 for(int i=0;i<a;i++) 44 str[i]='0';//讲a前面的位全部置0 45 str[a]=k; 46 } 47 int main() 48 { 49 scanf("%d",&n); 50 scanf("%s %s",str,set); 51 int len=strlen(str); 52 ans=0; 53 for(int i=len-1;i>=1;i--) 54 { 55 if(str[i]==set[i])//如果相等就往前移 56 continue; 57 solve(i-1,'1'); 58 ans++; 59 str[i]=set[i]; 60 } 61 if(str[0]!=set[0])//对于i=0做单独判断 62 ans++; 63 printf("%lld\n",ans); 64 return 0; 65 }