P2527[SHOI2001]Panda的烦恼(题解)
P.S.
此题较为毒瘤,需要开long long以及加优化。
普通的构造方法貌似不能过QwQ。
Problem.
给定一堆质因数,求这些质因数构成(乘积)的所有数中的第K小值。
Solution.
首先,我们一看到这道题,笔者第一时间想到要用STL中的set来构造。
于是就写了一个简单的代码(解释在代码注释中)。
因为小的数
#include<bits/stdc++.h>//万能头
using namespace std;
int n,k,a[105];set<int>s;//STL set万岁
int main()
{
scanf("%d%d",&n,&k),s.insert(1);//插入1
for(int i=1;i<=n;i++) scanf("%d",a+i);//读入n个质因数
for(int i=1;i<k;i++)//因为要求第k大,所以要删去k-1个比它小的数
{
int t=*s.begin();s.erase(s.begin());//把当前最小的拿出来并删去
for(int i=1;i<=n;i++) s.insert(t*a[i]);//构造出当前最小的能到达的所有数
}
return printf("%d\n",*s.begin()),0;//输出删去k-1个最小数后的第k个
}
然后结果我们一运行。。。
然后我们再来仔细读一读题目
比如说至多只包含质因数2,3的数有2,3,4,6,8,9,……
好罢被坑了,1是无法构造出来的,所以要求第k个质因数是第k+1个。
恭喜笔者绕过了第一个弯QAQ。
然后笔者再打出这样一份代码
#include<bits/stdc++.h>
using namespace std;
int n,k,a[105];set<long long>s;
int main()
{
scanf("%d%d",&n,&k),s.insert(1);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<=k;i++)//修改唯一一处:<k变成<=k
{
int t=*s.begin();s.erase(s.begin());
for(int i=1;i<=n;i++) if(t*a[i]<=2000000000) s.insert(t*a[i]);
}
return printf("%lld\n",*s.begin()),0;
}
样例是过了,但是
笔者仔细地看了看错误信息。
Wrong Answer. wrong answer On line 1 column 1, read -, expected 6.
好罢,知道了,没开long long。
恭喜笔者绕过了第二个弯。
然后笔者又打出了第三份代码
#include<bits/stdc++.h>
using namespace std;
int n,k,a[105];set<long long>s;//修改:int变成long long
int main()
{
scanf("%d%d",&n,&k),s.insert(1);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<=k;i++)
{
long long t=*s.begin();s.erase(s.begin());//修改:int变成long long
for(int i=1;i<=n;i++) s.insert(t*a[i]);
}
return printf("%lld\n",*s.begin()),0;
}
WA是不WA了,但是
笔者随便加了点优化。
#include<bits/stdc++.h>
using namespace std;
int n,k,a[105];set<long long>s;
int main()
{
scanf("%d%d",&n,&k),s.insert(1);
for(int i=1;i<=n;i++) scanf("%d",a+i);
sort(a+1,a+n+1);//排个序更快
for(int i=1;i<=k;i++)
{
long long t=*s.begin();s.erase(s.begin());
for(int i=1;i<=n;i++) if(t*a[i]<=2000000000) s.insert(t*a[i]);
//因为题目中已经说了,保证答案不超过2000000000。
//那么超过2000000000的肯定不需要加入set,一个优化
}
return printf("%lld\n",*s.begin()),0;
}
结果还是
于是笔者从整份代码来考虑,T的原因应该是在set中加入太多超过第K大的数了吧。
那么我们可以记录当前set的最大值。
如果的接下来构造的这个数已经大于最大值且set中有k个数了。
我们就可以break结束了。
然后加了这个优化之后,笔者顺利AC了这道题QAQ。
Coding.
#include<bits/stdc++.h>
using namespace std;
int n,k,f=1,a[105];long long mx,INF=2000000000;set<long long>s;
//f表示当前set中是否有k个数
int main()
{
scanf("%d%d",&n,&k),s.insert(1);
for(int i=1;i<=n;i++) scanf("%d",a+i),a[i]==1?(i--,n--):0;
sort(a+1,a+n+1),mx=1;//最大值变成当前唯一的一个1
for(int i=1;i<=k;i++)
{
long long t=*s.begin();s.erase(s.begin());
for(int i=1;i<=n&&t*a[i]<=INF;i++) if(f||a[i]*t<=mx) s.insert(t*a[i]),mx=max(mx,t*a[i]);
//首先,刚刚加的优化仍然有(在循环条件中)
//然后,这个判断条件就是刚刚说的那个break的反条件QAQ
f=((int)s.size()+i<=k);
//更新f,检查加入后是否set中有k个数
}
return printf("%lld\n",*s.begin()),0;
}
Ending.
写题解辛苦,管理大大求过,无耻求赞