[usaco3.1.3]humble
这道题想了很久想不到,只好看题解(在下服气),题解是666的,不用多说上代码。
第一个是官方题解:记录下到第i-1个丑数时,每一个素数枚举到哪一个丑数,然后直接从那个丑数继续开始枚举。
第二个是手写堆+set判重,每一次取出最小的数作为第i个丑数,然后枚举每一个素数扩展新元素加入堆,再用set判重。(但剪枝写的没有证明)
/* ID:abc31261 LANG:C++ TASK:humble */ #include<cstdio> #include<cstring> #include<map> #include<iostream> using namespace std; const int maxn=200,maxm=700000; long long num[maxn],hash[maxm+1],f[maxn],len,hum[maxm]; //f数组就是记录枚举到哪一个。 void add(int x) { int i=x%maxm,j=i+1; if (hash[i]==0)hash[i]=x; else { while (j!=i && hash[j]!=0)j=(j+1)%maxm; hash[j]=x; } } int check(int x) { int i=x%maxm,j=i+1; if (hash[i]==x)return 1; else { while (j!=i && hash[j]!=x && hash[j]!=0)j=(j+1)%maxm; if (hash[j]==x)return 1; } return 0; } int main() { int i,j,k,n,l,p,q; freopen("humble.in","r",stdin); freopen("humble.out","w",stdout); scanf("%d%d",&k,&n); memset(hash,0,sizeof(hash)); memset(f,0,sizeof(f)); for (i=1;i<=k;i++)scanf("%d",&num[i]); hum[1]=len=1; //为了方便,把1也看作一个丑数。 for (i=1;i<=n;i++) { int l=0; for (j=1;j<=k;j++) { while (check(num[j]*hum[f[j]+1])==1)f[j]++; if ((num[j]*hum[f[j]+1]<num[l]*hum[f[l]+1])|| l==0)l=j; //枚举 } hum[++len]=num[l]*hum[++f[l]]; add(hum[len]); } cout<<hum[len]<<endl; return 0; }
/* ID:abc31261 LANG:C++ TASK:humble */ #include<cstdio> #include<cstring> #include<set> #include<iostream> using namespace std; const int maxn=200,maxm=100000; set<long long> s; long long heap[maxm*4],len=0; int k,n,num[maxn]; long long get() { long long i=1,x=heap[1]; swap(heap[1],heap[len--]); while (i*2<=len) { int j=i*2; if (i*2+1<=len && heap[i*2+1]<heap[i*2])j=i*2+1; if (heap[i]>heap[j]) { swap(heap[i],heap[j]); i=j; } else break; } return x; } void put(long long x) { long long i=++len,j; heap[len]=x; while (i>1) { if (heap[i/2]>heap[i]) { swap(heap[i/2],heap[i]); i=i/2; } else break; } if (len>n)len=n; //这个直接剪的话没有证明(汗)。 } int main() { int i,j; long long x; freopen("humble.in","r",stdin); freopen("humble.out","w",stdout); memset(heap,0,sizeof(heap)); cin>>k>>n; for (i=1;i<=k;i++)scanf("%d",&num[i]); put(1); //把1看作一个丑数 for (i=1;i<=n;i++) { x=get(); for (j=1;j<=k;j++) if (s.count(num[j]*x)==0) { put(num[j]*x); s.insert(num[j]*x); } } cout<<get()<<endl; return 0; }