题意:S(1)="COFFEE",S(2)="CHICKEN" ,S(n) = S(n−2)+S(n−1),请输出 S(n) 中从第 k 个字符开始的10个字符(若不足10个输出到末尾即可),(1≤n≤500,1≤k≤min(|S(n)|,1012)
思路:那会好多人过了这题,就尝试去写了一下,然而我处理的是区间,答案输出是对的,但是莫名其妙的段错误,可能用区间处理递归太多了吧,后来看到xjl学姐过了,她用for循环模拟的递归,是对十个位置上每个字符进行处理,仔细想想,这样写的确比我的要好,太弱了,连递归都写不好~T_T 以下来自官方题解
记 f(i) 表示 S(i) 的长度,f(i) = f(i−2) + f(i−1).
递归调用 solve(n,k) 表示 S(n) 的第 k 个字符,
若 n≤2 直接返回答案,
n>2 时,若 k>f(i−2),调用 solve(n−1,k−f(n−2))否则调用 solve(n−2,k).
注意特判 k>f(n).
Code
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll t, n, k; ll f[58] = {0,6,7}; char s1[10] = "COFFEE", s2[10] = "CHICKEN"; void dfs(int n, ll k){ if(k>f[n]) return; if(n==1) printf("%c", s1[k-1]); else if(n==2) printf("%c", s2[k-1]); else { if(k>f[n-2]) dfs(n-1,k-f[n-2]); else dfs(n-2,k); } } int main() { for(int i=3;i<=57;i++) f[i]=f[i-1]+f[i-2]; //for (int i = 1; i <= 57; i++) printf("%lld ", f[i]); scanf("%d",&t); while(t--){ scanf("%d%lld", &n, &k); if(n>57) if(n&1) for(int i=0;i<10;i++) dfs(57,k+i); else for(int i=0;i<10;i++) dfs(56,k+i); else for(int i=0;i<10;i++) dfs(n,k+i); printf(" "); } return 0; }
至于为什么这里n只用计算到57,仔细看题目就知道k最大只能到1e12,因此n大到一定程度后,后面查找的其实还是用的前面的S(57)或者S(56),自己把f[i]打个表就知道了
学姐的代码:
#include<stdio.h> #define ll long long #define MAXM 1000000000015L ll T; ll len[505]; char* s1 = "COFFEE"; char* s2 = "CHICKEN"; ll noww[15][5]; int main() { scanf("%lld", &T); len[1] = 6; len[2] = 7; for(ll i = 3; i <= 500; i ++){ len[i] = len[i - 1] + len[i - 2]; if(len[i] > MAXM) len[i] = MAXM; } while(T --){ ll n, k; scanf("%lld%lld", &n, &k); for(int i = 0; i < 10; i ++){ if(k + i <= len[n]){ noww[i][0] = n; noww[i][1] = k + i; } else{ noww[i][0] = 0; noww[i][1] = 0; } } for(int i = n; i >= 3; i --){ for(int j = 0; j < 10; j ++){ if(noww[j][0] == i){ if(noww[j][1] <= len[i - 2]) noww[j][0] = i - 2; else{ noww[j][0] = i - 1; noww[j][1] = noww[j][1] - len[i - 2]; } } } } for(int i = 0; i < 10; i ++){ if(noww[i][0] == 1) printf("%c", s1[noww[i][1] - 1]); else if(noww[i][0] == 2) printf("%c", s2[noww[i][1] - 1]); } printf(" "); } return 0; }