P1885 Moo
题目描述
奶牛 Bessie 最近在学习字符串操作,它用如下的规则逐一的构造出新的字符串:
S(0) =S(0)= moo
S(1) = S(0) +S(1)=S(0)+ m + ooo + S(0) =+S(0)= moo + m + ooo + moo = moomooomoo
S(2) = S(1) +S(2)=S(1)+ m + oooo + S(1) =+S(1)= moomooomoo + m + oooo + moomooomoo = moomooomoomoooomoomooomoo
Bessie 就这样产生字符串,直到最后产生的那个字符串长度不小于读入的整数 NN 才停止。
通过上面观察,可以发现第 kk 个字符串是由:第 k-1k−1 个字符串 + m + (k+2(k+2 个 o) +o)+ 第 k-1k−1 个字符串连接起来的。
现在的问题是:给出一个整数 N(1≤N≤10 9 ),问第 NN 个字符是字母 m 还是 o?
输入格式
一个正整数 NN。
输出格式
一个字符,m 或者 o。
输入输出样例
输入
11
输出
m
说明/提示
样例解释:
由题目所知:字符串S(0) 是 moo, 现在要求第 11 个字符,显然字符串 S(0) 不够长;
同样 S(1)的长度是 10,也不够长;S(2) 的长度是25,够长了,S(2) 的第 11 个字符是 m,所以答案就输出 m。
思路
分治, 首先预处理一下第n个字符在被包含在第几个字符串里.然后在把这个字符串分成1,2,3三个区间(1区间和3区间是一模一样的字符),然后判断n在第几个区间,不断分治,将大问题分成几个小问题去求解,最后注意边界处理即递推到了第一个字符串.
#include<bits/stdc++.h>
using namespace std;
int a[100005],t;//t表示输入的那个字符在第几层
//a[i]表示第i层字符串的长度,比如a[0]=3,表示字符串“moo”
int cur(int x){//用来求出第x个字符在第几层,并且顺便保存了从a[0]开始的每一层有多少字符
int sum=3;//第0层
int k=1;
while(sum<x){//直到求出大于要求的字符长度的那个数组长度
sum=sum*2+1+k+2;
a[k]=sum;//第k层字符串有多少个
k++;
}
return k-1;//它的上一层即为所求
}
char check(int n,int t){//第n个字符,起初在第t层
if(t==0){
if(n==1) return 'm';
if(n==2||n==3) return 'o';
}
if(n<=a[t-1]) return check(n,t-1);如果在第1区间
if(n>a[t]-a[t-1]) return check(n-(a[t]-a[t-1]),t-1);//如果在第3间
if(n==a[t-1]+1) return 'm';//如果在第2区间
return 'o';//因为第2个区间时候1个'm'和k个'o'组成,所以n如果是第2区间的第一个数,则返回'm',否则返回'o'
}
int main(){
int n;cin>>n;
a[0]=3;
t=cur(n);//求出第n个字符在第几层
char ch=check(n,t);
cout<<ch;
return 0;
}