【伪题解】 [Offer收割]编程练习赛58

【A:最大的K-偏差排列】:

第一次在hiho卡一题,所以暴力了搜索了一下,70分,后面回来打表找规律,规律是有和K有关的周期。

当K<=N/2时,成周期交叉变化,最后尾部部分单独考虑。

当K>N/2时,有三个序列,分别是[K+1...N]  [K...N-K+1 ] [1..N-K]

自己的代码:

#include<bits/stdc++.h>
using namespace std;
int ans[110],N,K;
int main(){
    int pos=0,i,j;
    scanf("%d%d",&N,&K);
    if(K>=N-1) {
        for(i=N;i>=1;i--) ans[++pos]=i;
    }
    else if(K<=N/2){ //A 
        int tmp=N/(K*2);
        for(i=1;i<=tmp;i++){
            for(j=(i-1)*2*K+1;j<=(i-1)*2*K+K;j++) ans[++pos]=j+K;
            for(j=(i-1)*2*K+1;j<=(i-1)*2*K+K;j++) ans[++pos]=j;
        }
        if(K>=N-tmp*2*K-1) for(i=N;i>=tmp*2*K+1;i--) ans[++pos]=i; //a //最后一部分同理。 
        else {                                                     //b 
            for(i=K+1;i<=N-tmp*2*K;i++) ans[++pos]=i+2*tmp*K;
            for(i=K;i>N-tmp*2*K-K;i--) ans[++pos]=i+2*tmp*K;
            for(i=1;i<=N-tmp*2*K-K;i++) ans[++pos]=i+2*tmp*K;
        }
    }
    else {             //B 
        for(i=K+1;i<=N;i++) ans[++pos]=i;
        for(i=K;i>N-K;i--) ans[++pos]=i;
        for(i=1;i<=N-K;i++) ans[++pos]=i;
    }
    for(i=1;i<=N;i++) printf("%d ",ans[i]);
    return 0;
}
View Code

别人的段代码:

#include<bits/stdc++.h>
using namespace std;
int used[110];
int main(){
    int N,K;
    scanf("%d%d",&N,&K); 
    for (int i=1;i<=N;i++){
        int j=max(1,i-K),up=min(N,i+K);
        while(used[up]) up--;
        while(j<up&&(used[j]||(i<N&&j>=i+1-K))) j++;
        used[j]=1;
        printf("%d ",j);
    }
    return 0;
}
View Code

【B:孤独的字符】:

水题一个:对于每个字符,找到它做出贡献的范围,分别记录左边界L和右边界R,然后累计乘积。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=100010;
ll L[maxn],R[maxn],Laxt[30],ans;
char c[maxn]; 
int main()
{
    int N,i,j;
    scanf("%s",c+1);
    N=strlen(c+1);
    for(i=0;i<26;i++) Laxt[i]=0;
    for(i=1;i<=N;i++) {
        L[i]=Laxt[c[i]-'a'];
        Laxt[c[i]-'a']=i;
    }
    for(i=0;i<26;i++) Laxt[i]=N+1;
    for(i=N;i>=1;i--) {
        R[i]=Laxt[c[i]-'a'];
        Laxt[c[i]-'a']=i;
    }
    for(i=1;i<=N;i++) ans+=(ll)(i-L[i])*(R[i]-i);
    cout<<ans<<endl;
    return 0;
}
View Code

【C:秋天来了】:

一眼感觉是差分约束题,但是发现由于每个条件的(L,R)之间的点都要加限制,限制条件过多,不行。

所以直接暴力一点去更新区间(L,R);很明显可以加优化:如果(L,R)之间的最大值都比Ai小,那就没必要更新了。

所以实际上暴力区间(L,R)的次数不会太多。(但是比赛后验证了一下,直接把线段树部分去掉,暴力就可以过。。。。)

#include<bits/stdc++.h>
using namespace std;
const int maxn=100001;
int h[maxn],x[maxn],y[maxn];
int Max[maxn<<2];
void build(int Now,int L,int R){
    if(L==R) {
        Max[Now]=h[L]; return ;
    }
    int Mid=(L+R)>>1;
    build(Now<<1,L,Mid);
    build(Now<<1|1,Mid+1,R);
    Max[Now]=max(Max[Now<<1],Max[Now<<1|1]);
}
void update(int Now,int L,int R,int pos,int val){
    if(L==R) {
        Max[Now]=val; return ;
    }
    int Mid=(L+R)>>1;
    if(Mid>=pos) update(Now<<1,L,Mid,pos,val);
    else update(Now<<1|1,Mid+1,R,pos,val);
    Max[Now]=max(Max[Now<<1],Max[Now<<1|1]);
}
int qmax(int Now,int L,int R,int l,int r){
    if(l<=L&&r>=R) return Max[Now];
    int tmp=0,Mid=(L+R)>>1;
    if(l<=Mid) tmp=max(tmp,qmax(Now<<1,L,Mid,l,r));
    if(r>Mid) tmp=max(tmp,qmax(Now<<1|1,Mid+1,R,l,r)); 
    return tmp;
}
int main()
{
    int N,L,H,M,i,j;
    scanf("%d%d%d%d",&N,&L,&H,&M);
    for(i=1;i<=N;i++) h[i]=H;
    build(1,1,N);
    for(i=1;i<=M;i++) scanf("%d%d",&x[i],&y[i]);
    bool Flag=true;
    while(Flag){
        Flag=false;
        for(i=1;i<=M;i++){
            if(x[i]==y[i]) continue;
            if(x[i]<y[i]){
                if(qmax(1,1,N,x[i]+1,y[i]-1)>=h[x[i]]) {
                 for(j=x[i]+1;j<y[i];j++) 
                  if(h[j]>=h[x[i]]){
                     h[j]=h[x[i]]-1;Flag=true;
                     update(1,1,N,j,h[j]);   
                  }
                }
             }
             
            else {
                if(qmax(1,1,N,y[i]+1,x[i]-1)>=h[x[i]]){
                 for(j=x[i]-1;j>y[i];j--)
                  if(h[j]>=h[x[i]]){
                      h[j]=h[x[i]]-1;Flag=true;
                      update(1,1,N,j,h[j]);     
                  }
                }
            }
            
        }
    }
    for(i=1;i<=N;i++) printf("%d
",h[i]);
    return 0;
}
View Code

 【D:Nim森林】:

不如没有前面两步,就是最后一个石子输的Nim博弈类型。

忽略前面两步,输的情况是:

                  1,全部石子堆的石子个数都为1,而且石子堆数为奇。

                  2,至少有两堆大于1的石子堆,且石子堆的石子异或值为0。

根据两个情况,可以骗到一些分。。。(但是我手速慢了,最后慌慌张张提交,0分。。。输出“No”都有10分,妈蛋

                  1,假如只有一堆: 如果这一堆只有X=1个,那么必输;否则,胜利的代价是X-1。

                  2,假如全部堆都有Xi=1;那么胜利代价是N-2;

                  ...

                                 

原文地址:https://www.cnblogs.com/hua-dong/p/8998403.html