USACO3.1题目简析
chunlvxiong的博客
T1:Agri-Net
题意:给出N个牧场(1≤N≤100)以及它们两两之间连接的代价,求出将所有牧场连接在一起的最小代价。
裸的最小生成树问题。由于边比较多,使用prim算法。时间复杂度O(N^2)。
T2:Score Inflation
题意:有N个问题(1≤N≤10000),总时间为M(1≤M≤10000),每个问题有一个解决时间和分数。输出能够获得的最大分数,一个问题可以被解决多次。
经典完全背包问题,其中的思想很好。
正常的DP方程:dp[i][j]=max{dp[i-1][j-k*time[i]]+k*score[i]}。这样的时间复杂度是O(NM^2)的。
你允许同维的继承,同时先转移小的,后转移大的,方程变为:dp[i][j]=max(dp[i][j-1],dp[i][j-time[i]]+score[j]}。
然后你发现实际上这个方程完全可以压成一维。
这样做时间复杂度O(NM),空间复杂度O(M),在USACO评测机上跑得飞快。
T3:Humble Numbers
题意:给定K个素数(1≤K≤100),求由这K个素数相乘可以得到的第N(1≤N≤100000)小的数,答案保证≤2^31-1。
经典思路:堆
这个思路很好理解,首先把K个数全部压进堆中,然后取出堆顶元素X以及X出堆,对于与X相同的,一起出堆,然后把X*prime[1],X*prime[2],……X*prime[K]全部入堆,一直操作下去。时间复杂度O(Nlog?)
问题在于这个?很大,最大可以达到10000000(NK),时间仍然足够,但是USACO的16M内存是过不去的。
考虑下堆的优化:我们尽量避免重复元素的入堆。
因为有例如prime[2]*prime[1]*prime[2]=prime[1]*prime[1]*prime[2]这样的情况,所以你强制顺序:即对于已经乘有prime[X]的数,它不能再乘prime[1]……prime[X-1]了,它只能乘prime[X]……prime[K]。这样可以避免任何重复元素入堆。
然而问题是……好像堆的大小还是要开得很大,还是A不掉。
下面给出USACO的ANALYSIS:
我们将1视为一个丑数。
当我们有第k个丑数,并想要计算第k+1个丑数时,我们做如下操作:
对于每个素数p,找到最小丑数h,使得h*p大于第k个丑数,然后取最小的h*p作为第k+1个丑数。
这样时间复杂度为O(NK),而空间复杂度仅为O(N),就可以顺利A掉此题。
T4:Contact
题意:给出一个字符串(长度≤200000),输出N个出现次数最多的序列(长度为a~b(1≤a≤b≤12)之间,先输出出现次数多的)。如果出现次数相同,先输出长度小的。如果长度相同,按二进制大小排列。如果出现的序列个数小于N,输出存在的序列。
由于a,b均≤12,所以可能的字符串种类并不多。为了区分0,00这样的序列,对于一个序列,不仅要存其相应的十进制数,还要保存长度。这样种类数为2^12*12=49512种。
然后你就对于每个位置向后a到b的位置进行统计,并开个数组存放结果。最后将这个数组排个序,按序输出即可。时间复杂度O(200000*12)。
T5:Stamps
题意:有N种邮票(1≤N≤50,每种邮票面值不超过10000),最多贴K张(1≤K≤200),问能贴出的连续的最大面值是多少。
考虑用dp[i]表示面值为i最少要贴几张邮票,如果贴不出来用oo表示。
用a[i]表示第i种邮票面值,则:dp[i]=min{dp[i-a[j]]+1|1≤j≤N,且i>=a[j]}
如果发现一个dp[i]>k,那么说明答案为i-1。
答案上限为K*10000=2e6,所以总时间复杂度为O(2e6*N)=O(1e8)。
看上去要T,实际运行效率远不到这个上限,所以可以A掉此题。