@Junlier
2018-10-18T19:56:22.000000Z
字数 1297
阅读 1618
题解
给你个质数,让你求这个质数能乘起来组成的第大数(好大八大)
看到这个数据范围,很容易想到搜索对吧
但是又不能盲目地搜索,考虑
搜出前个和后个能拼出的所有状态
很显然随便算一下是存的下来的(不确定数组开多大就开个)
我们发现还是无法很快找到第大的答案对吧
这种时候就应该想到二分答案来解决,那么我们对答案二分
问题就转化成了给你一个数和两个数列,让你找出它在这两个数列中每个数列任选两个乘起来的数中排名为多少
这个就不是很难了,那两个指针扫一遍就完事了。。。
如果不知道怎么扫的话可以考虑看一看代码(如果你看得懂的话)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define ldb double
#define lst long long
#define rgt register int
#define N 20
#define pb push_back
using namespace std;
const lst Inf=1e18;
il int read()
{
int s=0,m=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();}
while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return m?-s:s;
}
lst n,K;
vector<lst> v[3];
lst p[N],Sz[3];
void Dfs(int rt,int now,lst ss)
{
if(now>n){v[rt].pb(ss),++Sz[rt];return;}
for(lst w=1;;w*=p[now])
{
Dfs(rt,now+2,ss*w);
if((1e18)/p[now]<w*ss)return;
//用除法是因为怕爆long long
}
}
int main()
{
n=read(),v[1].pb(0),v[2].pb(0);
for(rgt i=1;i<=n;++i)p[i]=read();
sort(&p[1],&p[n+1]),Dfs(1,1,1),Dfs(2,2,1);
sort(&v[1][1],&v[1][Sz[1]+1]);
sort(&v[2][1],&v[2][Sz[2]+1]);
lst le=1,ri=1e18,mid,tot,Ans;K=read();
while(le<=ri)
{
mid=(le+ri)>>1,tot=0;
for(rgt i=1,j=Sz[2];i<=Sz[1]&&j>=1;++i,tot+=j)
while(j&&mid/v[1][i]<v[2][j])--j;//用除法是因为怕爆long long
if(tot<K)le=mid+1;
else Ans=mid,ri=mid-1;
}return printf("%lld\n",Ans),0;
}