第一题
【题目及题号】跳高 superoj944
【题解】
方法一(繁):用DP。
方法二(简):发现一个性质,在找能跳到的最大高度时,每次都跳到极限位置一定最优,且跳的台子数量最少。
要跳得最多的话直接找到最高的高度,小于等于它的数量就是答案。
开心写sort。
【考试ING】
我最后十分钟出了组全是0的数据然后发现了自己的错。Orz还好发现了Orz。看来下次交卷前二十分钟就该好好检查了。
第二题
【题目及题号】证明 superoj945
【题解】
[方法一]:
Dijikstra + Heap
(一)时间复杂度:
建图O(m+n)
离散化O(nlogn)
Dijikstra+Heap O(nlogn)
(二)分析过程:
将题目抽象出来,相当于给了我们一些带权的线段,要求我们用最小的权值,覆盖坐标轴1~n的范围。
应该很容易得到的一个性质,对于当前已覆盖距离的右坐标R,可用的转移只有左界在[L,R]范围内的线段。
如图片所示,对于3号点,只能使用2~4或者2~5向前进行移动。【我们这里强制使转移有序,实际上先使用哪条线段不影响结果】
如果对于每一个出现的点向上一个点建一条权值为0的边,把读入的边界从较小的点向较大的点建一条边(单向);就可以保证,每一次向前都需要付出代价,每一次取已覆盖区间的起点不需要代价。那么1为起点,n为终点跑最短路即可。如果无法到达n,那么输出-1。
现在遇到了另外一个问题,n的范围是10^9,如果对每一个坐标整点建边,复杂度是不可接受的。我们观察后发现,实际上每一个m只会带来两个可能被转移的点,那么将出现的点离散化,最坏的情况是有O(2*m)个点。Dijikstra+Heap可以轻易过掉这个题。
(三)注意事项
本题数据很强,卡掉了SPFA,请自觉写dijikstra+Heap。
[方法二]:
DP+优先队列+二分答案
f[i]表示用到第i个线段最少的花费。
f[i] = min(f[j])+c[i]; (li<=rj)
因为右界和花费都是单增的,所以可以在单调的队列中进行二分。
[方法三]:
Dp+线段树
fi表示证明了li~n相等且使用了第i个数学家所需要的最少花费。
fi = min(f[j])+c[i]; (lj<=ri且rj>ri)复杂度O(m^2)
现在考虑优化,将l,r离散化之后,让数学家按照l排序。
维护一个数组Gi,Gi = min(fj | lj=i);
然后求fi时使用(1,ri)直接的最小值来更新就好了。
【考试ING】
其实到现在我都不知道我当时怎么把这道题转成图论做的。标算是DP+线段树。Orz。
不过这倒是又明确了一点,觉得自己没有办法继续优化Dp的时候可以去想想别的算法。
第三题
【题目及题号】伪造 superoj946
【题解】
这个问题正着考虑是不太好想的,因为当前的最优值可能会影响到之后的值。
所以我们倒着来做,这样有一个好处,去掉了问题的后效性。
即如果当前值最大,当扫到前面的时候结果不会变差。
第一部分判断数字可以怎么转化使用floyd即可。
第二部分就需要分情况讨论。
每一个实际分数都受到了两个分数的限制,一个是满分,一个是前一次(倒着扫的前一次)的分数。
下面简称满分为full,前一次为last,本次为now;
情况一:len(full)>len(now) && len(last)>len(now) 直接使当前每一位最大即可。
情况二:len(full)小于len(now) || len(last)小于len(now) 发现无论如何都无法求解,所以输出no退出。
情况三:len(full)==len(now) || len(last)==len(now) 那么取两者直接的最小值来限制now即可。
限制有几种,例如3000,当前数的最高位如果选择了3,而后面无论如何都无法全部变成0,就应该让最高位减小成2继续判断。
所以要用dfs来实现。
【考试ING】
考虑掉了3000那种情况,然后开开心心输出NO了。Orz
然后有一个比较有用的东西,就是比较完大小后把last和full较小的存在full里面,可以简化代码。(不然就要写两个dfs)
调试的时候发现的问题有:
1.傻逼地把lena打成了lenb,导致compare函数写错。
2.dfs当中不小心修改了限制条件,本来now是要用来判断是否可转的,然后我修改了。【见代码】
WRONG
if(limit){
for(int i=9;i>=0;i--)
if(able[ori[x][pos]-'0'][i] && i<=mf[x][pos]-'0'){
ori[x][pos] = i+'0';/*!!!!!!*/
if(i == mf[x][pos]-'0') dfs(x,pos+1,len,1);
else dfs(x,pos+1,len,0);
if(found) return;
}
}
RIGHT
if(limit){
for(int i=9;i>=0;i--)
if(able[ori[x][pos]-'0'][i] && i<=mf[x][pos]-'0'){
ans[x][pos] = i+'0';/*!!!!!!*/
if(i == mf[x][pos]-'0') dfs(x,pos+1,len,1);
else dfs(x,pos+1,len,0);
if(found) return;
}
}
最后!!!!!千万不要再交错代码!!!!!!
题目 | 预估分数 | 实际分数 |
---|---|---|
jump | 100 | 100 |
proof | 100 | 100 |
forge | 30~100 | 30 |