基本什么都没复习(最多前一天晚上看了一下今年的Practice Round),然后就冲上来做了。
scoreboard中搜索hdu.toraoh,可以看我的当时实际提交情况。
题意就不翻译了,这种英文阅读应该是能搞掂的,不然真没法在IT外企工作了。
本文地址:http://blog.csdn.net/fcxxzux/article/details/51873820
Problem A. Country Leader
设计一个结构体,能读入,读完顺手计算一下有多少不同的英文字母(注意英文字母不包括空格),然后顺手让这个结构体还能比较。最后不管你是O(nlogn)排序取最小,还是边读,边只保留最小,都行。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int T,Case=1;
struct Name{
char s[105];
int diff;
void get(){
gets(s);
set ss;
for(int i=0;s[i];++i){
if(s[i]!=' ')ss.insert(s[i]);
}
diff=ss.size();
}
bool operator<(const Name&b)const{
if(diff!=b.diff)return diff>b.diff;
return strcmp(s,b.s)<0;
}
}name[105];
int main(){
freopen("A-large.in","r",stdin);
freopen("A-large.txt","w",stdout);
int n;
for(scanf("%d",&T);Case<=T;Case++){
scanf("%d%*c",&n);
for(int i=0;i
造成了比较大的精神伤害(和麻烦)的一题……
我的思路是,反其道而行之,你从高处流下来流到低洼处不走了,我反过来,找低洼处,从下面往上灌水,直到找不到能灌水的低洼处为止。
具体实现上,首先是预处理。
按高度块合并,然后把外圈靠海的那些块标记为和大海这个特殊块相连。
之后还做了一堆,比如和大海相连的块出发bfs,找更高的块,也标记为边缘块,等(是否有用?我不确定)。
然后在中间,不靠海的块按高度放入优先队列。
之后,每次从优先队列里抓一块出来,搜索其边缘块,看看这个面积区域积水能积多深。
如果不能积水(边缘块比这块还矮),这块就不考虑了。
否则,直接水灌进去,和边上同高度的合并起来。
如果还是不和边缘块在一起,放回优先队列,否则,也不应该灌水了,不放回优先队列。
这样一直处理,直到优先队列为空。
最后,统计灌进去多少水,输出。
——你看我洋洋洒洒扯了这么麻烦的一个办法,然后我代码也有200行这么长……
#include
#include
#include
#include
#include
#include
#include
#include
#include
这题的重点是,不要被数学公式吓跑,不要考虑求导,把题读完。
题目描述部分的最后一句话是:
It is guaranteed that -1 < r < 1, and there is exactly one solution in each test case.
r=-1时,显然有f(-1)>=0,要有且仅有一解,显然f(1)<=0不说,在解和-1之间必然同号,解和1之间也是同号——那就是保证有[-1,x)是正的,(x,1]是负的。
那很直白的思路了:二分查找,是正的,缩小解区间左边,否则缩小解区间右边。
注意到这题要求精度达到1e-9,这不是什么低精度要求……
所以,二分的绝对误差要求高一点,中间的计算尽量用高精度的数据类型(听说C/C++要long double才能过,我在似乎无所谓的地方用了一下,也过了╮(╯_╰)╭)
——Google你真的没把B和C放反吗?
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int T,Case=1;
int n;
int val[105];
long double cal(double x){
long double v=-val[0]*pow(1+x,n);
for(int i=1;i<=n;i++){
v+=val[i]*pow(1+x,n-i);
}
return v;
}
int main(){
freopen("C-large.in","r",stdin);
freopen("C-large.txt","w",stdout);
for(scanf("%d",&T);Case<=T;Case++){
scanf("%d",&n);
for(int i=0;i<=n;i++)scanf("%d",&val[i]);
double l=-1.0,r=1.0,mid;
while(r-l>1e-12){
mid=(l+r)/2;
if(cal(mid)>0.0)l=mid;
else r=mid;
}
printf("Case #%d: %.12f\n",Case,l);
}
return 0;
}
事实上我被以前大家的过题情况骗了,然后想着小数据分拿到就好……
完全相反的是,D的大数据的分数是很好拿到的,你不需要成为动态规划玩得很溜的大神。D的大数据其实是,套路。
D的小数据的直白过法就是,分组背包。
然后我莫名其妙地开始脑抽,打死都要swap、clear,坑了好半天,最后剩20分钟的时候还是调通了……
代码很短,这个写法也不是这题的重点,贴一下,感兴趣自己上网查分组背包这东西。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int T,Case=1;
int m,n;
int Ki[10],Li[10];
int A[10][15],C[10][15];
vector last(1005),cur(1005);
int main(){
freopen("D-small-attempt1.in","r",stdin);
freopen("D-small1.txt","w",stdout);
for(scanf("%d",&T);Case<=T;Case++){
scanf("%d%d",&m,&n);
for(int i=0;i=premon;--l){
cur[l]=max(max(cur[l],last[l]),last[l-premon]+A[i][j]-A[i][Li[i]]);
}
}
last=cur;
}
printf("Case #%d: %d\n",Case,last[m]);
}
return 0;
}
注意到,N<=12,必须选8个
C(12,8)=495,很小啊。
然后考虑枚举选择的组合之后,怎么办?
还记得Practice Round的Problem B. Robot Rock Band吗?怎么做大数据呢?
4组,分成2部分,AB和CD,AB暴力计算完,放进HashMap,待用,之后枚举CD,在AB的HashMap中找,累加结果,复杂度变成了O(n^2+n^2*(1~logn))=O(n^2)
这种思想呢,你可以称作,meet in the middle。
概括起来就是,左边一半管自己的,怎么暴力怎么来,右边一半也是如此。把左右两边的结果结合起来的时候,使用一些高效的办法(单次操作一般O(1)、O(logn)的办法)。
这种思路能借鉴过来吗?Yes!
------以下是参考思路------
选出8个后,分成2部分处理,前4种卡牌和后4种卡牌。
对前4种卡牌,先暴力枚举,因为只有10档升级,所以最多有10^4种情况。
为了效率,以及之后与后半部分的结合的便捷性,我们考虑只留下有效数据。
所谓有效数据,就是对这种组合方案,不存在比他便宜或一样便宜的东西,战斗力更强。
很简单。
1、对之前算出来不超预算的情况,按价格从小到大,同价格按战力从大到小排序。
2、排序后,从前到后一个个看,记录前面最高战力,只保留能更新最高战力的数据(想一想为什么)
那对后半部分的处理就比较显然了。
同样的暴力枚举,是否只留下有效数据看你个人喜好(影响不大,这边再这么操作,那也只是常数优化)
对每种组合方案,在前4种卡牌中,找价格不超过剩余钱数的,战力最大的方案。根据这个结果,更新最优方案。
之前排序处理好有效数据的话,用二分查找,一次查找时间复杂度只要O(logn)。
最后考虑一下,我们的程序多久能跑完:
每组数据,要枚举C(12,8)=495种情况
每种情况下,计算量为10^4(前半部分的生成)+10^4*log(10^4)(排序)+10^4(筛选有效数据)+10^4*log(10^4)(后半部分的生成与二分查找)~= 280000
所以,一组数据大致计算量为495*280000=1.386e8
考虑到现在的电脑一般能做到1秒计算1.8e8(1秒计算1e8的,那是奔腾4),也就意味着,一组数据能在1秒之内计算出来,100组数据也就100秒,
你可以先小数据上确认正确性,然后下载大数据,运行,上传——别忘了大数据提交时间窗口是8分钟,跑100秒也不紧张。
实际上对Practice模式提供的大数据,我只跑了20秒,当然,我的代码里还有很多常数优化空间。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int T,Case=1;
ll m,n;
int Ki[15],Li[15];
ll A[15][15],C[15][15];
ll bestans;
bool sel[15];
int itemList[8];
struct Item{
ll money,power;
Item(){}
Item(ll a,ll b):money(a),power(b){}
bool operator<(const Item&b)const{
if(money!=b.money)return moneyb.power;
}
};
vector- tmp,t1;
void check(){
tmp.clear();t1.clear();
for(int i=Li[itemList[0]];i<=Ki[itemList[0]];++i)
for(int j=Li[itemList[1]];j<=Ki[itemList[1]];++j)
for(int k=Li[itemList[2]];k<=Ki[itemList[2]];++k)
for(int l=Li[itemList[3]];l<=Ki[itemList[3]];++l){
Item nnew(C[itemList[0]][i]+C[itemList[1]][j]+C[itemList[2]][k]+C[itemList[3]][l],
A[itemList[0]][i]+A[itemList[1]][j]+A[itemList[2]][k]+A[itemList[3]][l]);
if(nnew.money<=m)tmp.push_back(nnew);
}
sort(tmp.begin(),tmp.end());
ll maxpow=0;
for(int i=0;i
money+nnew.moneymoney+nnew.money>m)--it;
auto x=*it;
bestans=max(bestans,x.power+nnew.power);
}
}
}
void dfs(int depth,int last){
if(depth==8){
check();
return ;
}
if(8-depth>n-last)return;
for(int i=last+1;i
啰嗦了这么多呢……辛苦阅读到这里的各位了。