[LGR-113] 洛谷7月月赛

这是我第一次参加普及月赛,所以不要在意分数(

T3本来我的错误贪心能至少骗40pts,结果我自信地提交了一个算法,爆0..
T4我写了一个双指针,at first 我应该能有20-40pts。但是,经过我的反向优化,成功爆0


T1 gcd

给定T组数据,每一组有 \(l,r,x\)\(l\)\(r\) 范围内的数分别向下取整后的gcd
由于数据范围有 \(10^{18}\) 所以只能用 \(O(1)\) 的算法解决(别忘了long long)

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

int t;
long long r,l,x;

int main(){
    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        scanf("%lld %lld %lld",&l,&r,&x); 
        int tmp = r;
        bool flag=1;
        if(l/x!=r/x) flag=0;
        if(flag==0) printf("%d\n",1);
        else if(flag==1) printf("%d\n",r/x);
    }
}

T2 不等价交换法则

水题*2
因为只能买一个物品,所以排序后从后往前买就行
然后再从前往后扫一遍,尽可能买多的

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

int n;
long long w;
long long a[1000005];

bool cmp(long long x, long long y){
    return x<y;
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    scanf("%lld",&w);
    sort(a+1,a+n+1,cmp);
    int buy=-1;
    long long now=-1;//now表示拥有的商品
    for(int i=n;i>=1;i--){
        if(w>=a[i]){
            buy = i;
            now=a[i];
            break;
        }
    }
    long long cnt=0,ans=0;
    for(int i=1;i<=n;i++){
        if(cnt+a[i]<=now){
            ans++;
            cnt+=a[i];
        }
    }
    if((ans==0)&&(now!=-1)) ans = 1;
    printf("%lld",ans);
}

T3

假设c序列是固定的,我们可以从小到大枚举数列中出现过的数 \(k\) ,显然对于剩下的数而言,一定有 \(mex \leq k\)
为了方便计算,可以直接令 \(mex=k\),更优的答案一定会覆盖上一个答案。所以我们可以 枚举+取\(max(区间长度)\)
而当c序列不固定时,只需考虑\(a_x=b_x\)时情况即可,因为显然对于不等的情况,一定可以取到 \(a_x/b_x \neq x\)。所以本质是相同的

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

int a[1000007];
int b[1000007];
int l[1000007];
int ans[1000007];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",a+i);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",b+i);
    }
    for(int i=1;i<=n;i++){
        if(a[i]!=b[i]) continue;
        ans[a[i]]=max(ans[a[i]],i-l[a[i]]-1-a[i]);
        l[a[i]] = i;
    }
    for(int i=0;i<=n;i++){
        ans[i] = max(ans[i],n-l[i]-i);
    }
    int res=0;
    for(int i=0;i<=n;i++){
        res = max(res,ans[i]);
    }
    printf("%d",res);
}

T4

因为要使\(max-min\)最大,最优的结果一定会取到序列中的极值
因此,原式可化为\(w= \left|a_l-a_r\right|-(r-l+1)\)
而要拆绝对值,只需将序列正反分别遍历一遍,取最大值
进一步化简,可得出\(w=a_r-r-(a_l-l)-1\)
因此可以设\(c_i=a_i-i\)
对于每个枚举的\(i\),只需找到\(1到i-1\)中的最小值\(j\),计算区间贡献,取最大值即可

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

int a[10000007],b[10000007];

int main(){

    int i,j,n,m;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[n-i+1] = a[i];
    }
    int mina = 1e10+7,minb=1e10+7,maxx=0;
    for(int i=1;i<=n;i++){
        a[i] -= i;
        b[i] -= i;
        maxx=max(maxx,a[i]-mina);
        maxx = max(maxx,b[i]-minb);
        mina=min(mina,a[i]);
        minb=min(minb,b[i]);
    }
    printf("%d",maxx-1);
}
posted @ 2022-07-26 11:55  micawl  阅读(62)  评论(0)    收藏  举报