UOJ Logo heqingyu的博客

博客

普转提训练Week12

2018-06-05 22:08:28 By heqingyu

这周比赛十分弱鸡,题目难度比较高,所以分数比较绝望

T2:

发现两个字符串的本质是相同的

于是可以把他们都用“最小表示法”来表示出来

然后判断是否相同即可

code:

#include<bits/stdc++.h>
using namespace std;
char a[1000010],b[1000010];
int solve(char s[]){
    int len=strlen(s+1);
    for(int i=1;i<=len;i++) s[len+i]=s[i];
    int i=1,j=2,k=0;
    while(i<=len&&j<=len){
        for(k=0;k<=len&&s[i+k]==s[j+k];k++);
        if(k==len) break;
        if(s[i+k]>s[j+k]){
            i+=k+1;
            if(i==j) i++;
        }
        else{
            j+=k+1;
            if(i==j) j++;
        }
    }
    return min(i,j);
}
int main(){
    scanf("%s%s",a+1,b+1);
    int la=strlen(a+1),lb=strlen(b+1);
    int x=solve(a),y=solve(b);
    a[la+x]=b[lb+y]=0;
    if(la==lb&&!strcmp(a+x,b+y)){
        puts("Yes");
        printf("%s",a+x);
    }
    else puts("No");
    return 0;
}

T3:

我们发现2^k步之后,每个硬币的状态之和离他2^k远的硬币有关

于是用一种二进制拆解的方法,把T拆开,然后做,复杂度O(nlog(T))

code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int f[2][1000010];
int x=1,y,n,flag;
ll T;
ll get(ll mx){
    ll ans=2;
    while(ans<=mx) ans<<=1;
    ans>>=1;
    return ans;
}
int main(){
    scanf("%d%lld",&n,&T);
    for(int i=0;i<n;i++)scanf("%d",&f[0][i]);
    flag=T%2;
    T>>=1;
    while(T){
        ll t=get(T);
        T-=t;
        for(int i=0;i<n;i++)f[x][i]=(f[y][(i+n-t%n)%n]!=f[y][(i+t)%n])+1;
        swap(x,y);
    }
    if(flag){
        f[y][n]=f[y][0];
        for(int i=0;i<n;i++) printf("0 %d ",(f[y][i]!=f[y][i+1])+1);
    }
    else for(int i=0;i<n;i++) printf("%d 0 ",f[y][i]);
    return 0;
}

T4:

玄学做法

code:

#include<bits/stdc++.h>
using namespace std;
int n,b;
int a[100010];
int ans,pos,cnt;
int l[200010],r[200010];
int main(){
    scanf("%d%d",&n,&b);
    l[n]=r[n]=1;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(a[i]==b) pos=i,a[i]=0;
        if(a[i]<b) a[i]=-1;
        if(a[i]>b) a[i]=1; 
    }
    cnt=n;
    for(int i=pos-1;i>=1;i--) cnt+=a[i],l[cnt]++;
    cnt=n;
    for(int i=pos+1;i<=n;i++) cnt+=a[i],r[cnt]++;
    for(int i=0;i<=2*n;i++) ans+=l[i]*r[2*n-i];
    printf("%d",ans);         
    return 0;
}

T5:

我们可以利用DP的思想,设l[i]表示i左边第一个比h[i]高的下标

r[i]表示i右边第一个比h[i]高的下标

如果两个点可以看到,那么其中必定有一个矮的(或者同高)

于是我们枚举一个i,然后发现l[i]-r[i]这段区间中i只能够和l[i]与r[i]连接,并且不能连接到l[i]-r[i]以外

注意要判断l[i]是否和r[i]相等

code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,a[1000010];
int pos,b[1000010];
int same[1000010],maxn=-1;
int r[1000010],l[1000010];
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        if(a[i]>maxn){
            maxn=a[i];
            pos=i;
        }
    }
    for(int i=0;i<n;i++) b[i]=a[(pos+i)%n];
    b[n]=a[pos];
//    for(int i=0;i<n;i++) printf("%d ",b[i]);
    for(int i=n-1;i>=0;i--){
        r[i]=i+1;
        while(r[i]<n&&b[i]>b[r[i]]) r[i]=r[r[i]];
        while(r[i]<n&&b[i]==b[r[i]]){
            same[i]=same[r[i]]+1;
            r[i]=r[r[i]];
        }
    }
    for(int i=0;i<n;i++){
        l[i]=i-1;
        while(l[i]>0&&b[i]>=b[l[i]]) l[i]=l[l[i]];
    }
    ll ans=0;
    for(int i=0;i<n;i++){
        ans+=same[i];
        if(b[i]<b[0]){
            if(l[i]==0&&r[i]==n) ans++;
            else ans+=2;
        }
    }
    printf("%lld",ans);
    return 0;
}

评论

暂无评论