p5541题解
P5541 [USACO19FEB] Sleepy Cow Herding S
题目描述
Farmer John 的 NNN 头奶牛,总是会迷路走到农场上遥远的地方去!他需要你帮助将她们一起赶回来。
农场的草地大体是一块狭长的区域——我们可以将其想象成一条数轴,奶牛可以占据数轴上的任意整数位置。这 NNN 头奶牛现在正位于不同的整数位置,Farmer John 想要移动她们,使得她们占据 NNN 个相邻的位置(例如,位置 666、777、888)。
不幸的是,奶牛们现在很困,Farmer John 要让她们集中精力听从命令移动并不容易。任意时刻,他只能使得一头处在“端点”(在所有奶牛中位置最小或最大)位置的奶牛移动。当他移动奶牛时,他可以命令她走到任意一个未被占用的整数位置,只要在新的位置上她不再是一个端点。可以看到随着时间的推移,这样的移动可以使奶牛们趋向越来越近。
请求出使得奶牛们集中到相邻位置所进行的移动次数的最小和最大可能值。
输入格式
先输入一个整数 NNN(N≤100000N \leq 100000N≤100000),接下来输入 NNN 个数,表示 NNN 头奶牛的位置。
输出格式
输出的第一行包含 Farmer John 需要将奶牛们聚集起来所需进行的最小移动次数。第二行包含他将奶牛聚集起来能够进行的最大移动次数。
输入输出样例 #1
输入 #1
3
4
7
9
输出 #1
1
2
说明/提示
2019 USACO 二月月赛银牌组第一题
题目大意:
现在给定n个坐标,可以移动端点的坐标,注意:移动之后端点不可以再是端点,求解通过最少的步数和最多的步数使的它们在一起的值
思路:
注意移动之后不可以再是端点这个条件,之后分别考虑最小值和最大值,可以发现必须要将一段区间都填满,最小值可以枚举这个区间,用区间的大小减去目前拥有坐标所占有的数量就是需要移动的数量,这里求解坐标所占有的数量可以使用双指针,接下来求解最大值,最大值就是需要将所有中间的空格都走一次,但是第一个端点坐标必须要走到第二个端点坐标的下一位,这个是题目的限制,所以需要判断是将第一个点走到第二个的下一位还是将最后一个点走到最后一个点的前一位,判断取一个最大值即可,这里还需要注意一个点,最小值的一个特殊样例:
1 2 3 4 7
这个需要两步,因为不能将端点移动到端点,而中间还有隔得,所以需要两步
代码:
#include<bits/stdc++.h>
#define int long long
//#define ull unsigned long long
using namespace std;
//#define x first
//#define y second
//const int mod=19650827;
//const int N=1e5+10;
//int fac[N],invfac[N];
//int qmi(int a,int b,int p){int res=1;while(b){if(b&1)res=res*a%p;a=a*a%p;b>>=1;}return res;}
//int inv(int x){return qmi(x,p-2);}
//int C(int n,int m){if(n<0||m<0||n<m)return 0;return fac[n]*invfac[n-m]%p*invfac[m]%p;}
//void init(){fac[0]=1;for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%p;invfac[N-1]=inv(fac[N-1]);for(int i=N-2;i>=0;i--)invfac[i]=invfac[i+1]*(i+1)%p;}
//struct node{int v,w;bool operator < (const node &x)const{return w==x.w ? v>x.v : w>x.w;}};
//void dijkstra(const vector<vector<node>>&g,vector<int>&dist,vector<bool>&vis,int x){fill(dist.begin(),dist.end(),LLONG_MAX);fill(vis.begin(),vis.end(),false);
//dist[x]=0;priority_queue<node>q;q.push({x,0});while(q.size()){auto u=q.top().v;q.pop();if(vis[u])continue;vis[u]=true;for(auto [v,w]:g[u]){if(dist[v]>dist[u]+w){
//dist[v]=dist[u]+w;q.push({v,dist[v]});}}}}
//struct BIT{int n;vector<int>t;BIT(int _n=0){init(_n);}void init(int _n){n=_n;t.assign(n+2,0);}
//void add(int x,int v){for(;x<=n;x+=(x & -x))t[x]+=v;}int query(int x){int res=0;for(;x;x-=(x & -x))res+=t[x];return res;}};
//int calc_add(const vector<vector<int>>&s,int x1,int y1,int x2,int y2){return s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];}
//void calc_diff(vector<vector<int>>&d,int x1,int y1,int x2,int y2,int c){d[x1][y1]+=c;d[x2+1][y1]-=c;d[x1][y2+1]-=c;d[x2+1][y2+1]+=c;}
//int primes[N],cnt=0;bool st[N];
//void init1(){for(int i=2;i<N;i++){if(!st[i])primes[++cnt]=i;for(int j=1;primes[j]*i<N;j++){st[primes[j]*i]=true;if(i%primes[j]==0)break;}}}
//vector<int>factor[N];void init2(){for(int i=1;i<N;i++){for(int j=i;j<N;j+=i){factor[j].push_back(i);}}}
//int find(vector<int>&pre,int x){return pre[x]=(pre[x]==x ? x : find(pre,pre[x]));}
//void merge(vector<int>&pre,int x,int y){int fx=find(pre,x),fy=find(pre,y);if(fx==fy)return;pre[fx]=fy;}
//bool check(vector<int>&pre,int x,int y){return find(pre,x)==find(pre,y);}
//string add(string x,string y){if((int)x.size()<(int)y.size())swap(x,y);int n=x.size();int m=y.size();reverse(x.begin(),x.end());reverse(y.begin(),y.end());
//int d=0;string ans;for(int i=0;i<n;i++){int x1=(x[i]-'0');int y1=(i<m ? y[i]-'0' : 0);int sum=x1+y1+d;ans.push_back((sum%10)+'0');d=sum/10;}
//if(d>0)ans.push_back(d+'0');reverse(ans.begin(),ans.end());return ans;}
//string mul(string x,string y){if(x=="0"||y=="0")return "0";reverse(x.begin(),x.end());reverse(y.begin(),y.end());int x1=x.size();int y1=y.size();string ans;
//for(int i=0;i<x1;i++){int d=0;int val1=(x[i]-'0');for(int j=0;j<y1;j++){int val2=(y[j]-'0');int len=ans.size();int val=val1*val2+d;
//if(len<=i+j)ans.push_back((val%10)+'0');else val+=(ans[i+j]-'0'),ans[i+j]=((val%10)+'0');d=val/10;}int len=ans.size();int cur_pos=i+y1;
//while(d){if(cur_pos>=len)ans.push_back((d%10)+'0');else d+=ans[cur_pos]-'0',ans[cur_pos]=((d%10)+'0');d/=10;cur_pos++;}}reverse(ans.begin(),ans.end());return ans;}
//struct Seg_Tree{int n;vector<int>t,lz;Seg_Tree(int _n=0){init(_n);}void init(int _n){n=_n;t.assign((n<<2)+2,0);lz.assign((n<<2)+2,0);}
//void pushup(int o){t[o]=t[o<<1]+t[o<<1|1];}void update(int s,int e,int o,int x){t[o]+=x*(e-s+1);lz[o]+=x;}
//void pushdown(int s,int e,int o){if(!lz[o])return ;int mid=(s+e)>>1;update(s,mid,o<<1,lz[o]);update(mid+1,e,o<<1|1,lz[o]);lz[o]=0;}
//void add(int l,int r,int x,int s=1,int e=0,int o=1){if(e==0)e=this->n;if(l>e||r<s)return ;if(l<=s&&e<=r){update(s,e,o,x);return ;}pushdown(s,e,o);int mid=(s+e)>>1;
//add(l,r,x,s,mid,o<<1);add(l,r,x,mid+1,e,o<<1|1);pushup(o);}
//int query(int l,int r,int s=1,int e=0,int o=1){if(e==0)e=this->n;if(l>e||r<s)return 0;if(l<=s&&r>=e)return t[o];pushdown(s,e,o);int mid=(s+e)>>1;
//int x=query(l,r,s,mid,o<<1);int y=query(l,r,mid+1,e,o<<1|1);return x+y;}};
void solve(){int n;cin>>n;vector<int>a(n+1);for(int i=1;i<=n;i++)cin>>a[i];sort(a.begin()+1,a.end());auto calc_min=[&]()->int{if((a[n]-a[2]+1==n-1&&a[2]-a[1]>2)||(a[n-1]-a[1]+1==n-1&&a[n]-a[n-1]>2)){return 2;}int r=1;int mx=0;for(int l=1;l<=n;l++){while(r<=n&&a[r]-a[l]+1<=n)r++;mx=max(mx,r-l);//cout<<l<<' '<<r<<'\n';}return n-mx;};cout<<calc_min()<<'\n';cout<<max(a[n]-a[2],a[n-1]-a[1])+1-(n-1)<<'\n';
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);//init();//init1();//init2();int _=1;//cin>>_;while(_--)solve();return 0;
}
