P15263题解
P15263 Circle of Cows P
题目大意
有一个圆和 \(n\) 个特异点,我们需要找 \(m\) 条端点为特异点的弦(端点不能重复),使它们对应劣弧长度的最小值最大。
题目分析
我们考虑到一个性质:选中的弦必定两两相交。
证明:
把每对奶牛连成圆内的弦。设有两条不相交的弦,四个端点按圆周顺序为 \(p_1,p_2,p_3,p_4\),相邻点之间的弧长依次为 \(g_1,g_2,g_3,g_4\)。
原配对 \((p_1,p_2),(p_3,p_4)\) 的距离分别 \(\le g_1\) 和 \(\le g_3\),所以最小值 \(\le \min(g_1,g_3)\)。
改成相交的配对 \((p_1,p_3),(p_2,p_4)\) 后,距离分别是 \(\min(g_1+g_2, g_3+g_4)\) 和 \(\min(g_2+g_3, g_4+g_1)\)。这两个值都 \(\ge \min(g_1,g_3)\)。所以改成相交的配对不会变差,反复调整后可以假设所有弦两两相交。
由于对于一个选择的弦数量更多的答案,它可以少选择一些弦而保持答案不变,所以我们可以通过做后缀最大值来求答案。
那么我们可以先考虑钦定一条弦为最小的,然后算以它为最短弦求它最多可以选择多少条弦,最后做一个后缀最大值即可。
当钦定了一条弦为最小的的时候,显然我们再选弦的时候,必须一个端点在这条钦定的弦左边,另一个端点在钦定的弦右边,且这条弦长必须大于钦定的弦。所以我们考虑双指针,枚举左端点,并使用一个指针维护右端点。
代码
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int N=5e5+5;
int n,C;
int a[N];
int getdis(int x,int y)
{
if(x>n)x-=n;
if(y>n)y-=n;
int dis=abs(a[x]-a[y]);
return min(dis,C-dis);
}
int clac(int x,int y)
{
int d=getdis(x,y),l=y+1,r=x+n-1,num=1;
for(int i=x+1;i<=y-1;i++)
{
if(l>r)break;
if(getdis(i,l)<d)while(l<r&&getdis(i,l)<d&&getdis(i,l+1)>getdis(i,l))l++;
if(getdis(i,l)>=d)num++,l++;
}
return num;
}
int ans[N];
int main()
{
cin>>n>>C;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int num=clac(i,j);
ans[num]=max(ans[num],getdis(i,j));
}
}
for(int i=n/2;i>=1;i--)ans[i]=max(ans[i],ans[i+1]);
for(int i=1;i<=n/2;i++)cout<<ans[i]<<' ';
}

浙公网安备 33010602011771号