题意:给你n个位置,p个小炸弹,q个大炸弹;小炸弹可以连续炸w长度,大炸弹可以连续炸2*w长度
思路:显然二分答案求最小的w,问题在于如何check;
dp[i][j]表示炸完i之前所有点,使用j个小炸弹,最少需要多少个大炸弹;
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cmath> #include<string> #include<queue> #include<algorithm> #include<stack> #include<cstring> #include<vector> #include<list> #include<set> #include<map> #include<bitset> #include<time.h> using namespace std; #define LL long long #define pi (4*atan(1.0)) #define eps 1e-4 #define bug(x) cout<<"bug"<<x<<endl; const int N=2e3+10,M=5e5+10,inf=1e9+7,mod=1e9+7; const LL INF=1e18+10,MOD=1e9+7; int n,p,q; int nex[N][2]; int dp[N][N],a[N]; int check(int x) { for(int i=1;i<=n;i++) { nex[i][0]=lower_bound(a+1,a+n+2,a[i]+x)-a; if(2*x-inf+a[i]>0)nex[i][1]=n+1; else nex[i][1]=lower_bound(a+1,a+n+2,a[i]+x+x)-a; } for(int i=0;i<=n+1;i++) { for(int j=0;j<=p;j++) dp[i][j]=inf; } dp[1][0]=0; for(int i=1;i<=n;i++) { for(int j=0;j<=p;j++) { int v=nex[i][0]; dp[v][j+1]=min(dp[v][j+1],dp[i][j]); v=nex[i][1]; dp[v][j]=min(dp[v][j],dp[i][j]+1); } } for(int i=0;i<=p;i++) if(dp[n+1][i]<=q)return 1; return 0; } int main() { int T,cas=1; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&p,&q); for(int i=1;i<=n;i++) scanf("%d",&a[i]); if(p+q>=n) { printf("1 "); continue; } sort(a+1,a+1+n); a[n+1]=inf*2; int s=1; int e=inf,ans=-1; while(s<=e) { int mid=(s+e)>>1; //cout<<mid<<endl; if(check(mid)) e=mid-1,ans=mid; else s=mid+1; } printf("%d ",ans); } return 0; }