2016.11.10
Part.1 油滴扩展(box)
解题思路
暴力搜索(然而递归写错会很可怕),普遍用的stl求全排列然后搜的。注意求半径时要注意该点是否包含在前面已处理过的点扩展过的范围,此时这个点半径为0。四舍五入手打一个比较保险,(int)(x+0.5)。
for (int i=1;i<=n;i++)
a[i]=i;
do{
search();
judge();
}while (next_permutation(a+1,a+n+1));
int p=(int)(sq-ans+0.5);//int向下取整;
cout<<p<<endl;
Part.2.数列(sequence)
解题思路
又一道经典DP题,类似于最长公共子序列。f[i][j]表示前i个数删掉j个数得到的最优解:
for(int j=1;j<=n;j++)
{
for (inti=j;i<=n;i++)
{
if (i&&j)
f[i][j]=max(f[i-1][j-1],f[i-1][j]);
if (cf[i]+j==0&&i)
f[i][j]=max(f[i][j],f[i-1][j]+1);
}
}
part.3 SOFTWARE(software)
二分+多重背包(怎么又是DP……),首先我是根据“求最大值的最小值或最小值的最大值,有一定概率要用二分”的经验之谈看出来是个二分,然后直觉告诉我还要用个背包,结果一不留神想歪了以为要弄两个背包……DP完返回值处理的时候手抖加了个等号,Wa了3个点(上帝保佑竟然还能过7个……)
解题思路
直接二分答案,mid表示二分得到的完成时间,然后假设在这些时间第一个软件恰完成m个,这样就变成了一个容量为mid的多重背包,每个物品的件数k对应0~mid/t1[i],价值对应(mid-k*t1[i])/t2[i](充分利用第i个人工作的mid时间,枚举完成的软件1的模块数),目标是使软件2完成的模块数最多。这样D一遍再看结果和m的关系,ans<m说明无法完成任务,mid偏小,继续二分(mid+1,r)区间,否则二分(l,mid-1)区间。不得不说,要写出一个正确的二分确实不容易……
二分过程:
int ef(int l,int r)
{
if(l>r) return ans;
intmid=(l+r)/2;
if(search(mid))
{
ans=mid;
return ef(l,mid-1);
}
elsereturn ef(mid+1,r);
}
DP过程:
int search(int v)
{
memset(f,-127,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int k=0;k<=v/t1[i]&&k<=j;k++)
{
intk1=k,k2=(v-k*t1[i])/t2[i];
f[i][j]=max(f[i][j],f[i-1][j-k1]+k2);
}
}
}
if(f[n][m]<m)return false;
elsereturn true;
}
Part.4 黑匣子(blackbox)
最初并没有想到正解(平衡二叉树、二叉排序树并没有涉猎),随便写了个快排暴力过了30分。回过头看题解觉得神犇们真是机智……
解题思路(copy自前x届学长的题解,此法甚妙,蒟蒻口拙难以复述只好直接搬了)
1.首先维护一个小根堆A和一个大根堆B,时时保证B堆元素个数为(i-1)。
2. 对于每次add(k)操作,首先将k加入堆B并维护B的性质,再将B堆的堆顶元素弹出,插入堆A,同时维护A、B堆的性质。这样不难发现B堆便是前(i-1)小的数,而A的堆顶元素便是第i的数。
3.对于每次get操作,弹出并输出A的堆顶元素,并将这个元素插入B中,维护A、B堆的性质。
priority_queue<int,vector<int>,greater<int>> q1;
priority_queue<int,vector<int>> q2;
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for (int i=1;i<=n;i++)
cin>>a[i];
for (int i=1;i<=m;i++)
cin>>b[i];
int t=1,x,y;
for (int i=1;i<=n;i++)
{
q2.push(a[i]);
x=q2.top();
q2.pop();
q1.push(x);
bool ff=0;
while(i==b[t])
{
y=q1.top();
q1.pop();
q2.push(y);
cout<<y<<endl;
t++;
}
}