Acwing蓝桥杯集训·题解 week2

农夫约翰最喜欢的操作

分几步来:

  1. 要满足\(a_i-x\)整除\(x\)
    转化一下为,即满足\(a_i \equiv x \pmod M\) ,所以预处理,\(a_i=a_i \mod M\)

  2. 由第一步,我们可以知道\(x\in (0,M-1)\)

  3. 根据题意我们所求值 \(val=\sum_{i=1}^{i=n}|a_i-x|\)
    当val取最小值时,由于中位数定理,x是序列\(a_i\)的中位数

  4. 由于同余的性质,所以\(a_i \equiv a_i+M \pmod M\)

    • 所以x可以取不同的\(a_i\),就会有不同的序列,因此我们取每一个序列的中位数,比较每个序列的val,取最小
    • 当x取不同的\(a_i\)时,应该以\(a_i\)为中心建立一个序列,通过取余,将两边的\(a\)数量平衡
    • 为了方便这样处理可以\(a_i+M\)个数加到原序列之后,然后用前缀和快速求解
点击查看代码
#include<bits/stdc++.h>

using namespace std;
#define ll long long 
int n,x,k,m;
const int maxn=4e5+10;

int t;
int w[maxn];
ll sum[maxn];
 
void solve(){
	cin>>n>>m;
	
	for(int i=1;i<=n;++i) cin>>w[i],w[i]%=m;
	sort(w+1,w+1+n);
	for(int i=1;i<=n;++i) w[i+n]=w[i]+m;
	for(int i=1;i<=n*2;++i) sum[i]=sum[i-1]+w[i];
	ll res=1e18;
	for(int l=1;l<=n;++l){
		int r=l+n-1,p=(l+r)>>1;
		ll lt=(p-l+1)*(ll)w[p]-(sum[p]-sum[l-1]);
		ll rt=(sum[r]-sum[p])-(r-p)*(ll)w[p];
		res=min(res,lt+rt);
	}
	cout<<res<<"\n";
	return ;
}
signed main(){
	cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--){
    	solve();
	}
	return 0;
}

拐杖糖的盛宴

你会发现,写暴力就能过,很奇妙对吧

这题主要看你理解时间复杂度

  • 如果糖一直比第一个牛高,那么最多30次吃糖,之后的每一个糖都会被第一个牛吃掉
    因为牛每次都翻倍,\(2^{30}>10^9\)
  • 如果糖不比第一个牛高,那么每次吃糖,只有低第一头牛吃

综上,时间复杂度\((Nlog{10^9})\)

点击查看代码
#include<bits/stdc++.h>

using namespace std;
#define int long long 
int n;
const int maxn=2e5+10;
int a[maxn],b[maxn];
int nex[maxn];
int m;
signed main(){
    cin>>n>>m;
    int l=1;
    for(int i=1;i<=n;++i) {
        cin>>a[i];
    }
    for(int i=1;i<=m;++i){
    	cin>>b[i];
    	int now=0;
    	for(int j=1;j<=n;++j){
    		if(a[j]<b[i]){
    			if(now<a[j]){
    				int tx=now;
    				now=a[j];
    				a[j]+=(a[j]-tx);
				}
			}	
			else {
				a[j]+=(b[i]-now);
				break;
			}
		}
    }
    for(int i=1;i<=n;++i) cout<<a[i]<<" \n";
    return 0;
}

密接牛追踪2

其实题意很直接的,天数越长,所需的牛越少

我们只需要找到最小的那个区间感染完,所需的天数,然后以此来推出其他区间感染所需的最少的牛

设每个区间\([i,j]\)感染完的最长时间为d,易得d最大时\(d=\lceil \frac{i-j}{2} \rceil\)此时区间的最中间的一个头牛(如果不懂向上取整,就举几个例子)

此时我们得到最长的天数是r,设\(c_i\)为第i个感染牛的区间的数量,c的长度是x

所以需要的最少的牛\(\sum_{i=1}^{x} \lceil \frac{c_i}{2*r+1} \rceil=\lfloor \frac{c_i+2*r}{2*r+1}\rfloor\)

\(\lceil \frac{a}{b} \rceil= \lfloor \frac{a+b-1}{b} \rfloor\)
这个的证明,分别考虑a和b是否整除b即可,你会发现结果是一样的

点击查看代码
#include<bits/stdc++.h>

using namespace std;


int n;
string s;

vector<int>t;
int sum=0;
int main(){
    cin>>n;
    cin>>s;
    s=" "+s; 
    int r=n;
    for(int i=1;i<=n;++i){
        if(s[i]=='0') continue;
        int j=i;
        while(s[i+1]=='1' && i+1<=n) ++i;
        int c=i-j+1,d=(c-1)/2;//d是最小天数
        
        if(j==1 || i==n)
            d=c-1;
            
        r=min(r,d);
        t.push_back(c);
    }
    int res=0;
    for(auto c:t){
        res+=(c+r*2)/(2*r+1);//上下取整的转化
    }
    cout<<res<<"\n";
    return 0;
}

农夫约翰真的种地

看起来有点唬人,你如果注意到\(t_i\)是个排列,那么你可以将每个竹子按照\(t_i\)排序,设过了x天,竹子高度\(h_i^{`}=h_i+xa_i\),解不等式,求交集
注意移项时,不等式会不会变号

点击查看代码
#include<bits/stdc++.h>

using namespace std;
int t;
int n;
const int maxn=2e5+10;
int h[maxn],a[maxn];
int rk[maxn];
void solve(){
    cin>>n;
    for(int i=1;i<=n;++i) cin>>h[i];
    for(int i=1;i<=n;++i) cin>>a[i];
    for(int i=1;i<=n;++i){
       int x;cin>>x;
       rk[x+1]=i;
    }
    bool book=0;
    int l=0,r=1e9;
    for(int i=1;i<n;++i) {
        int x=h[rk[i]]-h[rk[i+1]];
        int y=a[rk[i+1]]-a[rk[i]];
        if(y>0) r=min(r,(int)(ceil)(x*1.0/y)-1);
        else if(y<0){
                l=max(l,(int)(floor)(x*1.0/y)+1);
        }
        else if(x<=0){
            r=-1;
            break;
        }
       
        
    } 
    if(r<l) {
        puts("-1");return ;
    }
    cout<<l<<endl;
}
int main(){
    cin>>t;
    while(t--){
        solve();
    }return 0;
}

多数意见

可以任意的选择,还可以重复的选,那么就很简单了

  1. 只要两个相邻的相同,那么就可以扩展相邻的一个一个变成相同的喜欢
  2. 如果两个相同的隔了一个,那么就也可以把中间的变成相同的喜欢,然后和1一样,全部变成相同的

综上,只要两个相同的距离不超过1就可以变成全部相同的

点击查看代码
#include<bits/stdc++.h>

using namespace std;


int t;
int n;
const int maxn=1e5+10;
bool book[maxn];
int a[maxn];
bool check=0;

void solve(){
    cin>>n;
    check=0;
    memset(book,0,sizeof(book));
    for(int i=1;i<=n;++i) cin>>a[i];
    for(int i=1;i<=n;++i){
        if(a[i+2]==a[i] && i<=n-2)
            book[a[i]]=1,check=1;
        if(a[i]==a[i+1] && i<=n-1) book[a[i]]=1,check=1;
    }
    if(check){
        for(int i=1;i<=n;++i) 
            if(book[i]) cout<<i<<" ";
        cout<<endl;
    }
    else puts("-1");
    return ;
}
int main(){
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
posted @ 2025-03-10 17:04  归游  阅读(30)  评论(0)    收藏  举报