「赛后总结」20220212 模拟赛题解

比赛传送门

T1吃

题意

\(n\) 个桌子,每个桌子上有两样吃的。想要选出连续的一段桌子,然后从每个桌子食物种类一样的食物吃下去。求他最多能吃多少个食物以及食物的最小标号。

思路

\(f_{i,j}\) 表示第 \(i\) 个桌子有多少个连续的种类为 \(j\) 的食物。

\(f_{i,j}=f_{i-1,j}+1\),暴力转移即可。

代码

#include <bits/stdc++.h>
#define _for(i,a,b) for(ll i=a;i<=b;++i)
#define for_(i,a,b) for(ll i=a;i>=b;--i)
#define ll long long
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;
int n,a[N],b[N],zl,f[N][10],ans,w;
int main(){
	scanf("%d",&n);
	_for(i,1,n){
		scanf("%d%d",&a[i],&b[i]);
		if(a[i]>b[i])swap(a[i],b[i]);
		f[i][a[i]]=f[i-1][a[i]]+1;
		f[i][b[i]]=f[i-1][b[i]]+1;
		int mx,z;
		if(f[i][a[i]]<=f[i][b[i]])mx=f[i][b[i]],z=b[i];
		else mx=f[i][a[i]],z=a[i];
		if(mx>ans||(mx==ans&&z<w))ans=mx,w=z;
	}printf("%d %d\n",ans,w);
	return 0;
}

T2糖

题意

\(m\) 颗糖,把它分给 \(n\) 个人。

\(i\) 个人对于分到糖果的预期值是 \(a_i\)

设第 \(i\) 个人得到了 \(b_i\) 颗糖果(\(b_i\le a_i\)),最小化: $$\sum^{i\le n}_{i=1}(a_i-b_i)^2$$

思路

首先我们要让 \(a_i-b_i\) 的值尽量平均(很好看出这个策略是正确的,例如 \(1^2+3^2>2^2+2^2\))。

令: $$c=\sum^{i\le n}_{i=1}a_i-m$$

我们可以让每一个 \(a_i-b_i\) 都等于 \(\lfloor\frac{c}{n}\rfloor\)

如果 \(a_i\le \lfloor\frac{c}{n}\rfloor\) ,则把 \({a_i}^2\) 累计入答案,把没用上的均摊给其它数而不是这个数

代码

#include <bits/stdc++.h>
#define _for(i,a,b) for(ll i=a;i<=b;++i)
#define for_(i,a,b) for(ll i=a;i>=b;--i)
#define ll long long
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;
ll n,m,a[N],sum,ans;
int main(){
	scanf("%lld%lld",&m,&n);
	_for(i,1,n){
		scanf("%lld",&a[i]);
        sum+=a[i];
	}
    sort(a+1,a+n+1);
    if(m>=sum)printf("0\n");
    else{
        ll c=sum-m,k=n;
        _for(i,1,n){
            ll pj=c/k;
            if(a[i]<=pj)c-=a[i],--k,ans+=a[i]*a[i];
            else break;
        }
        ans+=(k-c%k)*(c/k)*(c/k);
        ans+=(c%k)*(c/k+1)*(c/k+1);
        printf("%lld",ans);
    }
	return 0;
}

T3数

题意

给出一个长度为 \(n\) 的序列,求:

\[\sum^{1\le i\le j\le n}_{i=1,j=1}(\max^{k\le j}_{k=i}a_k-\min^{k\le j}_{k=i}a_k) \]

思路

首先我们把式子拆成:

\[\sum^{1\le i\le j\le n}_{i=1,j=1}\max^{k\le j}_{k=i}a_k-\sum^{1\le i\le j\le n}_{i=1,j=1}\min^{k\le j}_{k=i}a_k \]

考虑如何求这两坨。

对于每个 \(a_i(1\le i\le n)\),我们把它当成某些区间的最大值/最小值,看他在哪一个长度尽量大的区间是最大值/最小值,那么这个区间内 \(i\) 左边的点就是可行的左端点,右边的点就是可行的右端点。可行的左端点的数量 \(*\) 可行的右端点的数量,就是这些区间的个数。可行区间的个数乘 \(a_i\) 就是它产生的贡献了。

那我们又如何去求这个最大区间呢?

单!调!栈!

代码

#include <bits/stdc++.h>
#define _for(i,a,b) for(ll i=a;i<=b;++i)
#define for_(i,a,b) for(ll i=a;i>=b;--i)
#define ll long long
using namespace std;
const int N=3e5+10,inf=0x3f3f3f3f;
ll n,a[N],mn[N][2],mx[N][2],ans;
ll s[N],ts,t[N],tt;
map<ll,ll>mp;
int main(){
	scanf("%lld",&n);
	_for(i,1,n)scanf("%lld",&a[i]);
    a[0]=a[n+1]=inf;
    _for(i,1,n+1){
        while(ts>0&&a[s[ts]]<=a[i]){
            mx[s[ts]][0]=i-s[ts];
            ts--;
        }s[++ts]=i;
    }ts=0;
    for_(i,n,0){
        while(ts>0&&a[s[ts]]<a[i]){
            mx[s[ts]][1]=s[ts]-i;
            ts--;
        }s[++ts]=i;
    }a[0]=a[n+1]=0;
    _for(i,1,n+1){
        while(tt>0&&a[t[tt]]>=a[i]){
            mn[t[tt]][0]=i-t[tt];
            tt--;
        }t[++tt]=i;
    }tt=0;
    for_(i,n,0){
        while(tt>0&&a[t[tt]]>a[i]){
            mn[t[tt]][1]=t[tt]-i;
            tt--;
        }t[++tt]=i;
    }
    _for(i,1,n)ans+=a[i]*(mx[i][0]*mx[i][1]-mn[i][0]*mn[i][1]); 
	printf("%lld",ans);
	return 0;
}

T4膜

题意

咕咕咕

思路

咕咕咕

代码

#include <bits/stdc++.h>
#define _for(i,a,b) for(ll i=a;i<=b;++i)
#define for_(i,a,b) for(ll i=a;i>=b;--i)
#define ll long long
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;
ll t,n,m;
inline ll read(){
	ll x=0,w=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return w*x;
}bool check(ll md){
    __int128 c=md,sum=md;
    _for(i,0,m-2){
        c=c*(md-(i+1))/(i+2);
        if(c>=n)return 1;
        sum+=c;
        if(sum>=n)return 1;
    }return sum>=n;
}
int main(){
    t=read();
    while(t--){
        n=read(),m=read();
        ll l=1,r=n;
        while(l<r){
            ll mid=(l+r)>>1;
            if(check(mid))r=mid;
            else l=mid+1;
        }printf("%lld\n",r);
    }
	return 0;
}
posted @ 2022-02-12 16:54  K8He  阅读(54)  评论(2)    收藏  举报