题解 P1881 【绳子对折】

· · 题解

这题本身很水,但有一个很坑的地方,就是非整数点也要考虑

扫了一下题解,好像神犇都是用 +0.5 两个check()函数 之类的方法解决,这里我提供另外一个算法

*2

把位置,长度都*2,这样原来如果是小数(当然小数部分一定是0.5),现在的答案就会变为整数,处理的时候就会方便

首先标记节点位置

for (int i=1;i<=n;i++){
        int x;
        cin>>x;
        x*=2;//注意这里要*2 
        used[x]=1;
    }

只要一个check()

bool check(int l,int r,int mid)
{
    while (l>=0 && r<=L){
        while (!used[l]) l--;
        while (!used[r]) r++;
        if (l>=0 && r<=L){
            if (abs(l-mid)!=abs(r-mid)) return 0;
            l--;r++;
        }
    }
    return 1;
}

类似于快排,固定好边界,往左找节点,往右找节点,最后再判断一下边界,计算与mid的距离。如果不相等直接return 0,最后函数结尾return 1,表示该位置可行

然后是穷举

    for (int i=1;i<L;i++){
        int l=i-1,r=i+1;
        if (check(l,r,i) && i/2<L/2/*这里要注意,因为答案*2,所以还要判断这个点在原来的轴上是否存在*/){
            ans++;
        } 
    }

最后就是输出答案

CODE

#include<bits/stdc++.h>
using namespace std;
int n,L;
bool used[20005];
bool check(int l,int r,int mid)
{
    while (l>=0 && r<=L){
        while (!used[l]) l--;
        while (!used[r]) r++;
        if (l>=0 && r<=L){
            if (abs(l-mid)!=abs(r-mid)) return 0;
            l--;r++;
        }
    }
    return 1;
}
int main()
{
    cin>>n>>L;
    L*=2;
    for (int i=1;i<=n;i++){
        int x;
        cin>>x;
        x*=2;//注意这里要*2 
        used[x]=1;
    }

    int ans=0;
    for (int i=1;i<L;i++){
        int l=i-1,r=i+1;
        if (check(l,r,i) && i/2<L/2/*这里要注意,因为答案*2,所以还要判断这个点再原来的轴上是否存在*/){
            ans++;
        } 
    }
    cout<<ans<<endl;
    return 0;
 }