一道考验思维的好题,顺便总结求第k大问题的常规思路;
传送门:$>here<$
题意
给出初始串FX,每分形一次所有X替换为X+YF,所有Y替换为FX-Y。问$n$代字符串第$p$位起长度为$l$的串。
数据范围:$n \leq 50, p \leq 10^9, l \leq 50$
Solution
将求解一个串转化为求解第$k$个字符。这样的话只有求解$l$次字符就好了。
如果直接暴力去做,肯定从初始串开始暴力去一轮一轮的展开。而实际上并不需要展开每一个,因为只需要求一个字符。我只需要知道它的位置就可以了。
问题的转化
我们考虑找出在每一轮中,我们所要求的字符包含于那个字符中——去展开那个我们需要的字符。而如何找出它包含于哪个字符这个问题只与展开后的长度有关。
问题转化为求解一个字符展开若干轮之后的长度。这是个子结构,可以用$(s,n)$来表示。通过观察我们发现,有递推关系$(s,n)=2(s,n-1)+2$
透过题解看本质
求第k大的问题
很多题目会让我求第$k$个答案。例如求第$k$字典序的字符串;有时并不是单单排序能解决的,例如求字典序第$k$大的LIS;也可能像这道题一样,询问一个庞大答案中的某一截。
联系学过的内容
在我们学过的内容中也有许多要求第$k$大的——最显然的就是主席树了。当然还有普通平衡树求解第$k$大。
这二者都是通过比较左子树与$k$的大小来决策第$k$大的位置。也就是说,将求第$k$大的问题转化为了判定问题。往往(类似于二分答案)转化为判定问题会简单很多。
通过暴力考虑优化
求解第$k$大的暴力做法是全部求出来然后取第$k$大。那么我们可以思考,前面那些是否对第$k$个有意义,是否可以省略。跳过我们不需要求的,就好像剪枝一样
my code
注意$l$的做的时候可能太大了会爆。刚好题目要我们求的位置不超过10亿,因此长度对10亿取min即可。
/*By DennyQi 2018*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int MAXN = 10010; const int MAXM = 20010; const int INF = 0x3f3f3f3f; inline int Max(const int a, const int b){ return (a > b) ? a : b; } inline int Min(const int a, const int b){ return (a < b) ? a : b; } inline int read(){ int x = 0; int w = 1; register char c = getchar(); for(; c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘); c = getchar()); if(c == ‘-‘) w = -1, c = getchar(); for(; c >= ‘0‘ && c <= ‘9‘; c = getchar()) x = (x<<3) + (x<<1) + c - ‘0‘; return x * w; } int T,n,p,len,l[70]; inline char Char(int n, int k, bool c){ if(n == 0){ if(c == 0) return ‘X‘; else return ‘Y‘; } if(c == 0){ if(l[n-1] >= k) return Char(n-1,k,0); if(l[n-1]+1 == k) return ‘+‘; if(l[n-1]+1+l[n-1] >= k) return Char(n-1,k-(l[n-1]+1),1); if(l[n-1]*2+2 == k) return ‘F‘; } else{ if(k == 1) return ‘F‘; if(l[n-1]+1 >= k) return Char(n-1,k-1,0); if(l[n-1]+2 == k) return ‘-‘; if(l[n-1]*2+2 >= k) return Char(n-1,k-(l[n-1]+2),1); } } int main(){ l[0] = 1; for(int i = 1; i <= 50; ++i) l[i] = Min((l[i-1]<<1) + 2, 1000000100); T = read(); while(T--){ n = read(), p = read(), len = read(); for(int i = 0; i < len; ++i){ if(p+i==1) printf("F"); else printf("%c",Char(n,p+i-1,0)); } puts(""); } return 0; }
原文地址:https://www.cnblogs.com/qixingzhi/p/10349661.html