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;
}