[关闭]
@Junlier 2018-10-18T11:56:22.000000Z 字数 1297 阅读 1380

CF912E Prime Gift题解(搜索+二分答案)

题解

洛谷题目链接 CF题目链接

先翻译一下题意

给你个质数,让你求这个质数能乘起来组成的第大数(好大八大)

思路

看到这个数据范围,很容易想到搜索对吧
但是又不能盲目地搜索,考虑
搜出前个和后个能拼出的所有状态
很显然随便算一下是存的下来的(不确定数组开多大就开个

我们发现还是无法很快找到第大的答案对吧
这种时候就应该想到二分答案来解决,那么我们对答案二分
问题就转化成了给你一个数和两个数列,让你找出它在这两个数列中每个数列任选两个乘起来的数中排名为多少
这个就不是很难了,那两个指针扫一遍就完事了。。。
如果不知道怎么扫的话可以考虑看一看代码(如果你看得懂的话

Code(日常没注释)

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. #define rg register
  4. #define ldb double
  5. #define lst long long
  6. #define rgt register int
  7. #define N 20
  8. #define pb push_back
  9. using namespace std;
  10. const lst Inf=1e18;
  11. il int read()
  12. {
  13. int s=0,m=0;char ch=getchar();
  14. while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();}
  15. while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
  16. return m?-s:s;
  17. }
  18. lst n,K;
  19. vector<lst> v[3];
  20. lst p[N],Sz[3];
  21. void Dfs(int rt,int now,lst ss)
  22. {
  23. if(now>n){v[rt].pb(ss),++Sz[rt];return;}
  24. for(lst w=1;;w*=p[now])
  25. {
  26. Dfs(rt,now+2,ss*w);
  27. if((1e18)/p[now]<w*ss)return;
  28. //用除法是因为怕爆long long
  29. }
  30. }
  31. int main()
  32. {
  33. n=read(),v[1].pb(0),v[2].pb(0);
  34. for(rgt i=1;i<=n;++i)p[i]=read();
  35. sort(&p[1],&p[n+1]),Dfs(1,1,1),Dfs(2,2,1);
  36. sort(&v[1][1],&v[1][Sz[1]+1]);
  37. sort(&v[2][1],&v[2][Sz[2]+1]);
  38. lst le=1,ri=1e18,mid,tot,Ans;K=read();
  39. while(le<=ri)
  40. {
  41. mid=(le+ri)>>1,tot=0;
  42. for(rgt i=1,j=Sz[2];i<=Sz[1]&&j>=1;++i,tot+=j)
  43. while(j&&mid/v[1][i]<v[2][j])--j;//用除法是因为怕爆long long
  44. if(tot<K)le=mid+1;
  45. else Ans=mid,ri=mid-1;
  46. }return printf("%lld\n",Ans),0;
  47. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注