其他分享
首页 > 其他分享> > 【CF1015D】Walking Between Houses

【CF1015D】Walking Between Houses

作者:互联网

题意

​ 有一行房子,编号从 \(1\) 到 \(n\) ,起始位于房子1,每次移动可以到达除当前房子外任何一个(不能原地不动),移动距离为起点编号与终点编号差的绝对值。

​ 你需要进行 \(k\) 次移动,使移动距离的总和等于 \(s\) ,如果可行输出YES并输出每次移动的终点编号,否则输出NO。


思路

​ 先考虑不可行的情况,也就是 \(s\) 过大或 \(s\) 过小。

​ 若 \(k\leq s\leq k(n-1)\) ,则可行:

​ 首先算出最少需要几次移动可以使移动的总距离达到 \(s\) ,也就是每次移动都移动尽可能多的距离。

​ 假设至少需要 \(a\) 次移动可以达到 \(s\) ,此时必定 \(a\leq k\) ,对于\(a<k\) 的情况,我们可以将一次移动拆解为多次移动。比如某次移动为从1到 \(n\) ,则可以拆解为从1到2和从2到 \(n\),不难发现,一次距离为 \(l\) 的移动最多可以被拆解为 \(l\) 次距离为1的移动。我们可以通过拆解,将 \(a\) 次移动变为 \(k\) 次移动。

​ 思路不难,主要是代码实现的细节需要考虑下。


code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll maxn=1000000+10;
ll n,k,s;

int main()
{
    while(cin>>n>>k>>s)
    {
        if(k*(n-1)<s||k>s)
        {
            cout<<"NO\n";
            continue;
        }
        vector <int> ans,ans1;
        int x=s/(n-1),flag=1;
        for(int i=0;i<x;i++)
        {
            if(flag) ans.push_back(n);
            else ans.push_back(1);
            flag^=1;
        }
        if(x*(n-1)!=s)
        {
            if(x&1) ans.push_back(n-(s-x*(n-1)));
            else ans.push_back((s-x*(n-1))+1);
        }
        int len=ans.size(),from=1,to=ans[0],pos=0;
        while(len<k)
        {
            for(int i=from<to?from+1:from-1;i!=to;i>to?i--:i++)
            {
                if(len>=k) break;
                ans1.push_back(i);
                len++;
            }
            ans1.push_back(ans[pos]);
            pos++;
            from=to,to=ans[pos];
        }
        for(;pos<ans.size();pos++) ans1.push_back(ans[pos]);
        cout<<"YES\n";
        for(int num:ans1) cout<<num<<" ";
        cout<<"\n";
    }
    return 0;
}

标签:Walking,CF1015D,int,ll,pos,距离,Houses,每次,移动
来源: https://www.cnblogs.com/zjl4785/p/14666600.html