洛谷-题解 P2564【[SCOI2009]生日礼物】
作者:互联网
老师集训的题,猛然发现自己的解法居然独一无二!
解法就是:$dfs!$再加上2层2分。是不是有点惊人?而且并没有数据卡掉了我这种接近暴力的解法。
分析可得,$k$小的惊人,所以$dfs$也就可以了。而朴素的$dfs$绝对过不了,所以要加上优化。
外层的二分就是来优化的,其实更多的还是让思路更清晰,这个二分是二分答案。这样,$dfs$就成了判断了,可以进行剪枝了。
然而,这个优化仍微不足道,在$dfs$里有一个贪心的优化。
假设现在的范围为$[x,y]$,搜到了第$i$个品种,那么如果有位置在$[x,y]$间的,那么直接返回$dfs(i+1,x,y)$的值,因为这样必定为最优。如果没有,那么就返回$dfs(i+1,t,y)|dfs(i+1,x,l)$,($t$为小于$x$的最大值,$l$为大于$y$的最小值)这样,再加上前面的剪枝,就可以卡过时限了。
然而,还是担心会被卡,那就是里层二分的作用了。因为枚举上面的$t$可能会超时,因为位置都是有序的,可以用二分查找,这样时间效率提高了一些。
剩下的就是一下调试细节了。
下面是集训时交的代码
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
#include <queue>
using namespace std;
#define re register int
inline int read(){
int x=0,ff=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*ff;
}
int n,k,a[65][1000005],tt[65],opt,mx=0,mn=2147483647;
bool dfs(int i,int x,int y){
if(i>k)return (y-x)<=opt;
if(y-x>opt)return 0;
int j=1,t,ll=1,rr=tt[i],mid;
//while(a[i][j]<x&&j<=tt[i])j++;
while(ll<=rr){
mid=(ll+rr)>>1;
if(a[i][mid]>=x)rr=mid-1;
else ll=mid+1;
}
j=ll;
if(a[i][j]==x)return dfs(i+1,x,y);
if(j>tt[i])return dfs(i+1,a[i][tt[i]],y);
if(a[i][j]>=x&&a[i][j]<=y)return dfs(i+1,x,y);
if(j>1){
t=j-1;
if(y-a[i][t]<=opt)
if(dfs(i+1,a[i][t],y))return 1;
}
if(a[i][j]-x<=opt)return dfs(i+1,x,a[i][j]);
return 0;
}
bool ok(int x){
opt=x;
for(int i=1;i<=tt[1];i++){
if(dfs(2,a[1][i],a[1][i]))return 1;
}
return 0;
}
signed main(){
n=read();k=read();int l,r,mid;
for(int i=1;i<=k;i++){
tt[i]=read();
for(int j=1;j<=tt[i];j++){
a[i][j]=read();
}
mx=max(mx,a[i][tt[i]]);mn=min(mn,a[i][1]);
}
if(k==1){cout<<0<<endl;return 0;}
l=0;r=mx-mn;
while(l<=r){
mid=(l+r)>>1;
if(ok(mid))r=mid-1;
else l=mid+1;
}
printf("%d\n",l);
return 0;
}
考试后,听同学说洛谷有原题,于是交了上去,$AC$了。一阵高兴加激动。毕竟解法挺新奇。
然而......老师那儿爆零了!$rank$掉了10位。
原来数组开爆了,洛谷的评测是看运行空间。。。。
于是数组改成$vector$就过了。。。。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
#include <queue>
using namespace std;
#define re register int
inline int read(){
int x=0,ff=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*ff;
}
int n,k,tt[65],opt,mx=0,mn=2147483647;
vector<int>a[65];
bool dfs(int i,int x,int y){
if(i>k)return (y-x)<=opt;
if(y-x>opt)return 0;
int j=1,t,ll=0,rr=tt[i]-1,mid;
//while(a[i][j]<x&&j<=tt[i])j++;
while(ll<=rr){
mid=(ll+rr)>>1;
if(a[i][mid]>=x)rr=mid-1;
else ll=mid+1;
}
j=ll;
if(a[i][j]==x)return dfs(i+1,x,y);
if(j>=tt[i])return dfs(i+1,a[i][tt[i]],y);
if(a[i][j]>=x&&a[i][j]<=y)return dfs(i+1,x,y);
if(j>0){
t=j-1;
if(y-a[i][t]<=opt)
if(dfs(i+1,a[i][t],y))return 1;
}
if(a[i][j]-x<=opt)return dfs(i+1,x,a[i][j]);
return 0;
}
bool ok(int x){
opt=x;
for(int i=0;i<tt[1];i++){
if(dfs(2,a[1][i],a[1][i]))return 1;
}
return 0;
}
signed main(){
n=read();k=read();int l,r,mid;
for(int i=1;i<=k;i++){
tt[i]=read();
for(int j=1;j<=tt[i];j++){
//a[i][j]=read();
a[i].push_back(read());
}
mx=max(mx,a[i][tt[i]-1]);mn=min(mn,a[i][0]);
}
if(k==1){cout<<0<<endl;return 0;}
l=0;r=mx-mn;
while(l<=r){
mid=(l+r)>>1;
if(ok(mid))r=mid-1;
else l=mid+1;
}
printf("%d\n",l);
return 0;
}
所以,算紧了时间,不要忘了空间啊!!!
标签:洛谷,int,题解,ll,mid,dfs,return,include,P2564 来源: https://www.cnblogs.com/ffrxy01bt/p/11333348.html