HDUOJ-1041

HDUOJ-1041

题目大意:数字从1开始不断分裂,遇到0就变成10,遇到1就变成01。第一次变换从1变到01,第二次1001,第三次01101001,不断分裂下去。n从1取到1000
思路:一开始以为是模拟题,直到测试到50发现很慢了,后来才发现是找规律题,满足f(n)=f(n-1)+2*f(n-2)的规律。数据很大,要用二维数组存放或者字符串,这里用的是字符串处理大数

修改前代码:

//一开始的模拟思路
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
using namespace std;

map<int,string> mp;	//记录已经出现过的结果减少递归次数
int consecutive_zeros(string str){	//统计连续两个0的次数
	int pairs=0,start=0;
	while(start<str.length()-1){
		if(str[start]=='0'&&str[start+1]=='0'){
			pairs++;
		}
		start++;
	}
	return pairs;
}

string transformation(string str){	//分裂变换
	string ret="";
	for(int i=0;i<str.length();i++){
		if(str[i]=='0') ret+="10";
		else ret+="01";
	}
	return ret;
}

string DFS(string str,int start,int end){	//生成分裂字符串
	if(start==end) return str;
	if(mp.find(start)!=mp.end()) return DFS(mp[start],start+1,end);
	else mp[start]=DFS(transformation(str),start+1,end);
	return DFS(mp[start],start+1,end);
}

int main(){
	string start="1";
	int n;
	while(~scanf("%d",&n)){
//		cout<<DFS(start,0,n)<<endl;
		cout<<consecutive_zeros(DFS(start,0,n))<<endl;
	}
	system("pause");
	return 0;
}

修改后的代码:

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
using namespace std;

map<int,string> mp;

string multiply(string s1,string s2){	//字符串按照2*s1+s2规律相乘
	int carry=0,i,j;
	string str="";
	for(i=s1.length()-1,j=s2.length()-1;i>=0&&j>=0;i--,j--){
		int tmp=(s1[i]-'0')*2+(s2[j]-'0')+carry;
		carry=tmp/10;
		str+=to_string(tmp%10);
	}
	while(j>=0){
		int tmp=(s2[j]-'0')+carry;
		carry=tmp/10;
		str+=to_string(tmp%10);
		j--;
	}
	if(carry>0)
		str+=(carry+'0');
	reverse(str.begin(),str.end());
	return str;
}

string f(int n){	//规律
	string ret="";
	if(n==1) return "0";
	if(n==2) return "1";
	else{
		string s1,s2;
		if(mp.find(n-2)!=mp.end()) s1=mp[n-2];
		else{
			mp[n-2]=f(n-2);
			s1=mp[n-2];
		}
		if(mp.find(n-1)!=mp.end()) s2=mp[n-1];
		else{
			mp[n-1]=f(n-1);
			s2=mp[n-1];
		}
		ret=multiply(s1,s2);
	}
	return ret;
}

int main(){
	int n;
	mp[1]="0",mp[2]="1";
	while(~scanf("%d",&n)){
		cout<<f(n)<<endl;
	}
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值