3 条题解

  • 1
    @ 2025-3-6 11:48:01

    孩子们,调代码真有趣

    第一问是结论,非常得简单。


    如果不行,我们就双指针。

    对了,如果你是 for 套 while ,千万不要忘了更新 mid。

    #include<bits/stdc++.h>
    #define R(x) x=read()
    #define int long long
    #define N 100005
    using namespace std;
    inline int read() {
    	int x=0,y=1;
    	char e=getchar();
    	while(e<'0'||e>'9') {
    		if(e=='-')y=-1;
    		e=getchar();
    	}
    	while(e>='0'&&e<='9') {
    		x=(x<<1)+(x<<3)+(e-'0');
    		e=getchar();
    	}
    	return x*y;
    }
    int n,m,mon;
    int x[N],s[N];
    int ans=1;
    signed main() {
    	R(n),R(m),R(mon);
    	for(int i=1; i<=n; ++i) {
    		R(x[i]);
    	}
    	sort(x+1,x+1+n);
    	int sum=0;
    	for(int i=1; i<=n; ++i) {
    		sum+=abs(x[n/2+1]-x[i]);
    	}
    	if(sum<=mon) {
    		cout<<sum<<"\n";
    		return 0;
    	}
    	for(int i=1; i<=n; ++i) {
    		s[i]=s[i-1]+x[i];
    	}
    	int l=1,r=1;
    	while(l<=n&&r<=n){
    		int mid=(r+l+1)/2;
    		if(r<n&&s[r+1]-s[mid]-x[mid]*(r+1-mid)+x[mid]*(mid-l)-(s[mid-1]-s[l-1])<=mon)++r;
    		else ++l,++r;
    		ans=max(ans,r-l+1);
    	}
    	cout<<ans;
    	return 0;
    }
    
    • 0
      @ 2025-10-7 14:24:06

      第一问还是比较简单的,假设开会地点左边有3个牛舍,右边有2个牛舍,那么开会地点每往左移一个单位,总路程-3+2=-1,也就是要尽可能让左右两边牛舍数量相同,自然就选在中位数的位置

      如果钱不够,考虑使用双指针,在过程中不断计算总花费,如果过多就左端点右移,注意要及时更新mid。 code:

      #include<bits/stdc++.h>
      using namespace std;
      const int N=1e5+5;
      int n,m,a[N],maxx=0;
      long long ans,s,h=0,c[N];//记得开long long!!!
      int main(){
      	//freopen("meeting.in","r",stdin);
      	//freopen("meeting.out","w",stdout);
      	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
      	cin>>n>>m>>s;
      	for(int i=1;i<=n;i++) cin>>a[i];
      	sort(a+1,a+1+n);
      	for(int i=1;i<=n;i++){
      		c[i]=a[i]-a[i-1];
      	}
      	for(int i=2;i<=n/2+1;i++) ans+=(i-1ll)*c[i];
      	for(int i=n;i>=n/2+2;i--) ans+=(n-i+1ll)*c[i];
      	if(ans<=s){
      		cout<<ans;
      	}else{
      		int f=1,r,mid;
      		for(r=2;r<=n;r++){
      			mid=(f+r)>>1;
      			h+=a[r]-a[mid];
      			while(h>s){
      				f++;
      				mid=(f+r)>>1;
      				h-=(a[mid]-a[f-1]); 
      				if(f==r) h=0;
      			}
      			maxx=max(maxx,r-f+1);
      		} 
      		cout<<maxx;
      	}
      	return 0;
      } 
      
      
      • 0
        @ 2025-3-6 9:36:10

        这道题你需要先知道一个性质:

        中位数的位置召集奶牛,一定是最优的


        证明:证明:

        aia_i 排序,设开会的地点在 xx 处,xx 左侧有 PP 头奶牛,右侧有 QQ 头奶牛。若 P<QP<Q ,则每右移1,距离之和就会减小 QPQ-P。同理,若 P>QP>Q ,则左移更优。因此,当 P=QP=Q 时为最优。

        证毕证毕


        因此,预处理的代码如下

        long long calc(int l,int r){
        	if (l==r) return 0ll;
        	long long mid=(l+r)>>1, tot=l-r+1;
        	long long res=(sum[r]-sum[mid])-(sum[mid-1]-sum[l-1])-(tot&1?0:a[mid]);
        	return res;
        }
        
        
        //在main()中
        if (calc(1,n)<=s){
        	printf("%lld",calc(1,n));
        	return 0;
        }
        

        可是,怎么去找一个区间使其合法呢?

        第一眼想到的是暴力枚举每一个区间。但是这样太劣了

        注意到如果有一个区间是合法的,那么以后就没有必要遍历比它小的区间了

        因此可以用双指针解决,:

        1. 如果区间合法,把右指针右移

        2. 如果区间不合法,把两个指针同时右移

        便有AC代码声,此处无声胜有声

        #include<iostream>
        #include<cstdio>
        #include<algorithm>
        
        using namespace std;
        
        long long n,m,s,a[100005],sum[100005],ans;
        
        long long calc(int l,int r){
        	if (l==r) return 0ll;
        	long long mid=(l+r)>>1, tot=r-l+1;
        	long long res=(sum[r]-sum[mid])-(sum[mid-1]-sum[l-1])-(tot&1?0:a[mid]);
        	return res;
        }
        
        int main(){
        	scanf("%lld%lld%lld",&n,&m,&s);
        	for (int i=1;i<=n;i++){
        		scanf("%lld",a+i);
        	}
        	sort(a+1,a+n+1);
        	for (int i=1;i<=n;i++){
        		sum[i]=sum[i-1]+a[i];
        	}
        	if (calc(1,n)<=s){
        		printf("%lld",calc(1,n));
        		return 0;
        	}
        	long long l=1,r=1;
        	while (l<n && r<n){
        //		cerr<<"---"<<l<<" "<<r<<"  "<<calc(l,r+1)<<"\n";
        		if (calc(l,r+1)<=s){
        			r++;
        			ans=max(ans,r-l+1); 
        		}
        		else{
        			l++; r++;
        		}
        	}
        	printf("%lld",ans);
        	return 0;
        }
        
      • 1

      信息

      ID
      58
      时间
      1000ms
      内存
      256MiB
      难度
      8
      标签
      (无)
      递交数
      95
      已通过
      13
      上传者