2022/4/28

142 篇文章 0 订阅
142 篇文章 1 订阅

Motarack's Birthday

脑子坏掉了,连这道题都没有想出来,绝对值最大值一定是与数组中与-1相邻着的最大值或最小值相关,只要找出这两个数除以2就是k了,m也就好求了;

(9条消息) B. Motarack’s Birthday_Meteor_995的博客-CSDN博客

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf=1e16;
const ll mod=1e9+7;
const ll N=1e5;
ll t,n,a[100005];
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%lld",&t);
	while(t--){
        scanf("%lld",&n);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        ll maxx=0,minn=1e9;
        for(int i=1;i<=n;i++){
            if(a[i]!=-1&&(a[i-1]==-1||a[i+1]==-1)){
                maxx=max(maxx,a[i]);
                minn=min(minn,a[i]);
            }
        }
        ll k=(maxx+minn)/2;
        for(int i=1;i<=n;i++)
            if(a[i]==-1) a[i]=k;
        ll ans=0;
        for(int i=1;i<n;i++)
            ans=max(ans,abs(a[i]-a[i+1]));
        printf("%lld %lld\n",ans,k);
	}
	return 0;
}

Non-zero Segments

如果两个不相交(端点重合也算不相交)的子段都是0的话,那我们只能去填两个数,但如果他们相交的话我们就只需填一个很大的数就可以了,而且也可以这么想,如果有一段子段为0了,假设是在第i个位置为0的,那么i前面的数就都没用了,因为要想i后面的数与i前面的数相加不等于0,那么最好的方法就是在i前面插一个大数,那么i后面的数就不会再和i前面的数有任何关系了,要有关系也只是和i有关系,然后这个sum要如何求,要如何判断在i点有没有sum(j,i)==0(j<i)呢?我们可以看一下样例1,求出他们的前缀和s[]

可以看出 s[1]==s[4],说明a[2]+a[3]+a[4]==0,进一步得出只要当前的s[i]在之前出现过,那就说明当前的子段和为0,那就需要插数了,具体实现看代码;

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf=1e16;
const ll mod=1e9+7;
const ll N=1e5;
ll n,a[200005];
map<ll,ll>mp;
int main(){
	//freopen("in.txt","r",stdin);
        scanf("%lld",&n);
        ll sum=0,ans=0,pos=1;
        mp[0]=0;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            sum+=a[i];
            if(mp[sum]>=pos||sum==0){
                ans++;sum=a[i];
                pos=i;
                mp[sum]=i;
            }
            mp[sum]=i;
        }
        printf("%lld\n",ans);
	return 0;
}

P2327 [SCOI2005]扫雷 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

只要确定第一个格子的情况,后面的格子也就确定了,可以手摸一下第二列全是1的情况;

所以只要看看第一个格子有雷或无雷是否合法就行了答案也就是在0,1,2三种情况

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf=1e16;
const ll mod=1e9+7;
const ll N=1e5;
ll n,ans=2,b[10005],a[10005];
void check(){
    for(int i=2;i<=n+1;i++){
        b[i]=a[i-1]-b[i-1]-b[i-2];
        if(b[i]!=1&&b[i]!=0){
            ans--;break;
        }
        if(i==n+1&&b[i]!=0){
            ans--;break;
        }
    }
}
int main(){
	//freopen("in.txt","r",stdin);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    b[0]=0;
    b[1]=1;
    check();
    b[1]=0;
    check();
    printf("%lld\n",ans);
	return 0;
}

P7333 [JRKSJ R1] JFCA - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

倍增加二分的思想,因为点i确定后满足条件的j与i的长度一定是递增的,所以可以使用二分,但要如何才能确定所枚举的区间符合条件呢,借助倍增,可以o(1)的判断,由于这是一个环,所以我们既要向左找也要向右找,外加枚举的这层空间,所以需要开三倍的空间;

【题解】P7333 [JRKSJ R1] JFCA - 欣程 - 洛谷博客 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf=1e16;
const ll mod=1e9+7;
const ll N=1e5;
ll n,a[300005][50],b[300005];
void rmq(){
    for(int j=1;j<=30;j++)
    for(int i=1;i+(1<<j)-1<=n*3;i++)
    a[i][j]=max(a[i][j-1],a[i+(1<<j-1)][j-1]);
}
ll ask(ll l,ll r){
    ll k=log2(r-l+1);
    return max(a[l][k],a[r-(1<<k)+1][k]);
}
int main(){
	//freopen("in.txt","r",stdin);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i][0]),a[i+n][0]=a[i+n+n][0]=a[i][0];
    for(int i=1;i<=n;i++) scanf("%lld",&b[i]),b[i+n]=b[i+n+n]=b[i];
    rmq();
    //for(int i=1;i<=n+1;i++) cout<<ask(1,i)<<endl;
    ll len=n/2;
    for(int i=n+1;i<=2*n;i++){
        ll ans=inf,l=i-len,r=i-1,mid;
        if(ask(l,r)>=b[i]){
            while(l<=r){
                mid=l+r>>1;
                if(ask(mid,i-1)>=b[i]){
                    ans=min(i-mid,ans);
                    l=mid+1;
                }
                else r=mid-1;
            }
        }
        l=i+1,r=i+len;
        if(ask(l,r)>=b[i]){
            while(l<=r){
                mid=l+r>>1;
                if(ask(i+1,mid)>=b[i]){
                    ans=min(mid-i,ans);
                    r=mid-1;
                }
                else l=mid+1;
            }
        }
        if(ans!=inf) printf("%lld ",ans);
        else printf("-1 ");
    }
	return 0;
}

P7404 [JOI 2021 Final] とてもたのしい家庭菜園 4 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

经过仔细的观察后感觉就是用差分,但是没想到是枚举临界点,额,,其实也想到了,但是我想到的是n方枚举,,,所以就没写,瞎搞了一个处理方式就交上去了,果断wa,最后看题解才知道要用两个数组x,y,来枚举x[i],y[i+1]分别代表1~i是升序所用的步数和i+1~n是降序所用的步数,然后每次枚举ans=min(ans,max(x[i],y[i+1]))就行,至于如何求这两个数组呢?对于x来说,只有b[i]<=0才会对x产生影响,所以就是x[i]=b[i]<=0?x[i-1]-b[i]+1:x[i-1];y也同理;

题解 【JOI 2021 Final】 とてもたのしい家庭菜園 4 - 麻衣の家 - 洛谷博客

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf=1e18;
const ll mod=1e9+7;
const ll N=1e5;
ll n,a[200005],b[200005],x[200005],y[200005];
int main(){
	//freopen("in.txt","r",stdin);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),b[i]=a[i]-a[i-1];
    for(int i=2,j=n;i<=n;i++,j--){
        x[i]=(b[i]<=0?x[i-1]-b[i]+1:x[i-1]);
        y[j]=(b[j]>=0?y[j+1]+b[j]+1:y[j+1]);
    }
    ll ans=inf;
    for(int i=1;i<=n;i++)
        ans=min(ans,max(x[i],y[i+1]));
    printf("%lld\n",ans);
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值