博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
「Algospot」龙曲线DRAGON
阅读量:5173 次
发布时间:2019-06-13

本文共 2363 字,大约阅读时间需要 7 分钟。

一道考验思维的好题,顺便总结求第k大问题的常规思路;

传送门:

题意

给出初始串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 
#include
#include
#include
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

你可能感兴趣的文章
nginx安装手册
查看>>
动态将ASPX生成HTML网页并将网页导出PDF
查看>>
Find Backpacker Jobs in Australia
查看>>
面试题:return和finally执行
查看>>
Heroku第三方服务接入指南(二)
查看>>
MSRA专访摘要
查看>>
团队作业4
查看>>
第四次团队作业--选题
查看>>
记录专用
查看>>
一句实现jquery导航栏
查看>>
从零开始学 Web 之 Ajax(五)同步异步请求,数据格式
查看>>
场景分析:用户登录界面场景分析
查看>>
条形码生成包 BarCodeToHTML.cs(以颜色为背景的完整版)(下载的完整版)
查看>>
数据库事务的四大特性以及事务的隔离级别
查看>>
电脑屏幕保护眼睛
查看>>
有用的东西
查看>>
如何开启VMware串口
查看>>
数据库
查看>>
常见Struts、Hibernate、Spring、J2EE、ibatis、Oracle等开发框架架构图及其简介
查看>>
Java为何大行其道
查看>>