1 条题解

  • 0
    @ 2025-8-24 23:11:48

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Purslane
    AFO

    搬运于2025-08-24 23:11:48,当前版本为作者最后更新于2025-04-04 17:00:50,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Solution

    如果一个匹配的两个端点位置分别是 xxyy,他们会把整个圆周化为两个部分——假设一个部分为 w1w_1 个白点和 b1b_1 个黑点,另一个部分是 w2w_2 个白点和 b2b_2 个黑点。

    则这条线最多和 $\min\{w_1,b_2\} + \min\{w_2,b_1\} = \min\{w_1+b_1,w_2+b_2\}$ 条线相交(注意到 w1+w2=b1+b2=nw_1+w_2=b_1+b_2=n)也就是 dis(x,y)1\text{dis}(x,y)-1,其中 dis\rm dis 是环上两点的距离。

    我们先最大化 dis(bi,wi)1\sum \text{dis} (b_i,w_i) -1

    看看这个图:

    如果求红色点之间的距离,我们可以将其中一个红色的点对称到其对径点处,即计算下方红点和橙点的距离(用 nn 减去他们)。

    因此问题变为:环上给了若干个白点和黑点,将其配对,最小化距离(为什么要最小化而不是直接最大化?因为圆上的距离本质上是两种方案取最小值。而如果先取最小值再尝试最大化一些东西,会导致出很多问题。。)

    如果是序列上做这件事情,显然每条边会被经过的次数为:其左边的黑点总数与白点总数差的绝对值。所以我们不难猜测,最终的结果是——先匹配某个黑点和白点,然后不断移动他们顺时针方向下第一个黑点和第一个白点。有了这个结构,我们已经可以证明这种算法取到的解就是答案。

    显然至少有一条边不会被经过,所以我们考虑选一个位置出来断环成链。

    假设把 11n+nn+n 断开,记录 preipre_i 为:i\le i 的黑点个数减去白点个位数。

    那么假设我们实际上在 (p,p+1)(p,p+1) 处断开,则新的 prei=preipreppre'_i=pre_i - pre_p

    所以我们要最小化 i=1n+npreiprep\sum_{i=1}^{n+n} |pre_i-pre_p|

    选中位数就好了。复杂度 O(nlogn)O(n \log n),如果换成桶排可以做到 O(n)O(n)

    #include<bits/stdc++.h>
    #define int long long 
    #define ffor(i,a,b) for(int i=(a);i<=(b);i++)
    using namespace std;
    const int MAXN=1e6+10;
    int n,pre[MAXN];
    string S;
    signed main() {
    	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    	cin>>n>>S,S="&"+S;
    	ffor(i,1,n+n) if(S[i]=='B') pre[i]++;
    	else pre[(i+n-1)%(n+n)+1]--;	
    	ffor(i,1,n+n) pre[i]+=pre[i-1];
    	sort(pre+1,pre+n+n+1);
    	int ans=(n-1)*n;
    	ffor(i,1,n+n) ans-=abs(pre[i]-pre[n]);
    	cout<<ans/2;
    	return 0;
    }
    
    • 1

    信息

    ID
    11742
    时间
    2000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者