切蛋糕
题目描述
有一个蛋糕,它是由长度是L的二进制组成的。现在需要把蛋糕切K-1刀,这样蛋糕就会被切成K份,每一份蛋糕其实就是一段连续的二进制,而且每一份蛋糕的二进制不能有前导0。小LW今年5岁了,所以她希望把每一份蛋糕的二进制转为十进制之后,都是5的幂,即可以表示成5^X,其中X是整数。求满足题意的最小的正整数K。如果无法完成任务,输出-1。
输入格式
多组测试数据。
第一行,一个整数R,表示有R组测试数据。 1 <= R <= 25。
每组测试数据格式如下:
第一行,一个整数L。 1 <= L <= 50。
第二行,L个二进制数字,0或者1。
输出格式
共R行,每行一个整数。
输入/输出例子1
输入:
11
9
101101101
7
1111101
5
00000
9
110011011
10
1000101011
27
111011100110101100101110111
49
1101100011010111001001101011011100010111011110101
4
0101
4
1001
50
11111111111111111111111111111111111111111111111111
14
10111001110011
输出:
3
1
-1
3
-1
5
1
-1
-1
50
4
样例解释
无
题目来源
思路
详细的地方看注释吧o(╥﹏╥)o,这道题感觉自己暴力了一波,但是为什么题目发布者把它放进递推里面。。。
这里大致说一下:
首先为了省一些时间,直接就打了一个5的n次幂的二进制串,注意任何非零数的0次幂等于1!
#include<iostream> using namespace std; int main(){ for(int i=0;i<=23;i++){ long long temp=1; for(int j=1;j<=i;j++) temp*=5;//pow(5,i) bool a[100]={}; int len=1; while(temp!=0){ a[len++]=temp&1;//或temp%2 temp>>=1;//或temp/=2 } for(int j=len-1;j>=1;j--) cout<<a[j]; cout<<'\n'; } return 0; }
然后你要做的就是从左往右找,假如第一刀都切不上去,那自然就可以返回ERROR了,可以的话先切一刀,剩下的字符串再继续递归,可能出现多种情况,所以要扫一遍取ans。
然后输出最后的答案。。。(允许我水一行字数)
然后就没了。
完整代码
#include<iostream> #include<cstring> #define ERROR 100000000 using namespace std; string s[25]; int f(string temp){//递归代码,注意理解 if(temp.size()==0) return 0;//如果字符串长度为0,就是字符串已经切完,返回0 if(temp[0]=='0') return ERROR;//切出来的二进制串不能有前缀0,返回ERROR int ans=ERROR;//因为后面取最小值,开局取最大ERROR for(int i=1;i<=23;i++){ //遍历每一个可能切成的值为5次幂的二进制串 if(temp.size()>=s[i].size()&&temp.substr(0,s[i].size())==s[i]){ //判断是否可以切出这样的一段 int tmp=f(temp.substr(s[i].size(),temp.size()-s[i].size())); //继续往下切二进制串 //如果切到最后发现不可行也会返回ERROR,一直递归回来,所以可以放心写 if(tmp==ERROR) continue; //不能切直接跳过,避免出现可能的BUG ans=min(ans,tmp+1); //要找的是切成的最少份数 } } return ans;//返回答案 /* 或者也可以写成这样: return ans==ERROR?-1:ans; 这样ask()函数里就不用再判断 */ } inline void pow_5_n(){//s[i]等于pow(5,i)的二进制串,为了节省时间,可以提前打表 s[1]="1";//注意1=pow(5,0) s[2]="101"; s[3]="11001"; s[4]="1111101"; s[5]="1001110001"; s[6]="110000110101"; s[7]="11110100001001"; s[8]="10011000100101101"; s[9]="1011111010111100001"; s[10]="111011100110101100101"; s[11]="100101010000001011111001"; s[12]="10111010010000111011011101"; s[13]="1110100011010100101001010001"; s[14]="1001000110000100111001110010101"; s[15]="101101011110011000100000111101001"; s[16]="11100011010111111010100100110001101"; s[17]="10001110000110111100100110111111000001"; s[18]="1011000110100010101111000010111011000101"; s[19]="110111100000101101101011001110100111011001"; s[20]="100010101100011100100011000001001000100111101"; s[21]="10101101011110001110101111000101101011000110001"; s[22]="1101100011010111001001101011011100010111011110101"; s[23]="1000011110000110011110000011001001101110101011001001"; //pow(5,23)>pow(2,50),取到5的23次幂就够了 } inline void ask(){ int len; string str; cin>>len;//依据样例输入长度,虽然用不上 cin>>str; int rans=f(str); if(rans==ERROR) cout<<-1<<'\n';//依题意,无法完成任务输出-1 else cout<<rans<<'\n'; } int main(){ pow_5_n();//预处理 int r; cin>>r;//样例数量 while(r--) ask(); return 0; }