ZR 集训 Day30 - 模拟赛

ooliver OI

前言

今天是集训最后一天。。。

题目:

排列游戏

我们发现,想要字典序最小,肯定第一个填 1 是最优的,这样以来后面每个位置的奇偶性都确定了,我们直接按照从小到大放就行。

但是有一个特例,就是当 n[PARSE ERROR: Undefined("Command(\"mod\")")]4=3 的时候,第一个放 1 没有合法解,只能放 2。

代码:

C++

#include
using namespace std;

int c,T,n;

signed main(){
    scanf("%d%d",&c,&T);
    while(T--){
        scanf("%d",&n);
        if(n%4==3){
            for(int i=1;i*4
`#include
using namespace std;

int c,T,n;

signed main(){
    scanf("%d%d",&c,&T);
    while(T--){
        scanf("%d",&n);
        if(n%4==3){
            for(int i=1;i*4n;i++) printf("%d %d %d %d ",4*i-2,4*i-3,4*i-1,4*i);
            printf("%d %d %d\n",n-(n%4)+2,n-(n%4)+1,n-(n%4)+3);
        }
        else{
            for(int i=1;i*4n;i++) printf("%d %d %d %d ",4*i-3,4*i-2,4*i,4*i-1);
            if(n%4==1) printf("%d\n",n-(n%4)+1);
            else if(n%4==2) printf("%d %d\n",n-(n%4)+1,n-(n%4)+2);
            else printf("\n");
        }
    }
    return 0;
}`

时间线

当我们固定 r1 时,需要寻找一个 r2 使得:

mini=1r1ai=maxi=r2+1nai-mexi=r1+1r2ai

易证 maxi=r2+1nai-mexi=r1+1r2ai 具有单调性,所以二分找到满足条件的 r2 的区间即可。

代码:

C++

#include
using namespace std;

#define int long long
const int N=1e6+5;
int c,T,n;
int a[N],cnt[N],pre[N],mex[N],lg[N],st[20][N];

int qmax(int l,int r){
    int k=lg[r-l+1];
    return max(st[k][l],st[k][r-(1>c>>T;
    while(T--){
        cin>>n;
        for(int i=1;i>a[i];
        pre[1]=a[1];
        for(int i=2;i=1;i--){
            if(a[i]=1) mex[i-1]=now;
        }
        for(int i=2;i>1]+1;
        for(int i=1;i>1;
                int F=qmax(i+1,mid)-mex[mid];
                if(F>=L) fl=mid,r=mid-1;
                else l=mid+1;
            }
            if(fl==-1) continue;
            if(qmax(i+1,fl)-mex[fl]!=L) continue;
            l=i+1,r=n-1;
            while(l>1;
                int F=qmax(i+1,mid)-mex[mid];
                if(F
`#include
using namespace std;

#define int long long
const int N=1e6+5;
int c,T,n;
int a[N],cnt[N],pre[N],mex[N],lg[N],st[20][N];

int qmax(int l,int r){
    int k=lg[r-l+1];
    return max(st[k][l],st[k][r-(1k)+1]);
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>c>>T;
    while(T--){
        cin>>n;
        for(int i=1;in;i++) cin>>a[i];
        pre[1]=a[1];
        for(int i=2;in;i++) pre[i]=min(pre[i-1],a[i]);
        for(int i=0;in+2;i++) cnt[i]=0;
        int now=0;
        for(int i=n;i>=1;i--){
            if(a[i]n) cnt[a[i]]++;
            while(cnt[now]) now++;
            if(i-1>=1) mex[i-1]=now;
        }
        for(int i=2;in;i++) lg[i]=lg[i>>1]+1;
        for(int i=1;in;i++) st[0][i]=a[i];
        for(int k=1;klg[n];k++) for(int i=1;i+(1k)-1n;i++)
            st[k][i]=max(st[k-1][i],st[k-1][i+(1(k-1))]);
        int ans=0;
        for(int i=1;in-2;i++){
            int L=pre[i],l=i+1,r=n-1,fl=-1,fr=-1;
            while(lr){
                int mid=(l+r)>>1;
                int F=qmax(i+1,mid)-mex[mid];
                if(F>=L) fl=mid,r=mid-1;
                else l=mid+1;
            }
            if(fl==-1) continue;
            if(qmax(i+1,fl)-mex[fl]!=L) continue;
            l=i+1,r=n-1;
            while(lr){
                int mid=(l+r)>>1;
                int F=qmax(i+1,mid)-mex[mid];
                if(FL) fr=mid,l=mid+1;
                else r=mid-1;
            }
            if(fr==-1) continue;
            ans+=fr-fl+1;
        }
        coutans"\n";
    }
    return 0;
}`

暂存

对于一个二元组 (i,j)(j[PARSE ERROR: Ampersand]gt;i),考虑计算如果想要 ai 换到 aj 后面又多少种可能性。

首先,对于 i=1,我们只需暂存 ai,并保证 ai+1 到 aj 都不被暂存即可,可能性为 2n-1-(j-i)。

对于 i[PARSE ERROR: Ampersand]gt;1,我们不仅需要满足以上条件,还要保证 ai-1 不会被暂存,可能性就是 2n-2-(j-i)。

所以对于 ai,aj,如果 aiaj,贡献就是总可能性减去交换的可能性。

对于 i=1 我们可以直接记录答案;对于 i[PARSE ERROR: Ampersand]gt;1,我们会发现,固定 j 时乘法分配律一下就变成单点修改区间查询问题了,用一个树状数组维护即可。

代码:

C++

#include
using namespace std;

#define int long long
const int N=2e5+5;
const int mod=998244353;
int c,T,n;
int a[N],b[N],p2[N],inv[N];

inline int fpow(int x,int y){
    int res=1;
    while(y){
        if(y&1) (res*=x)%=mod;
        (x*=x)%=mod,y>>=1;
    }
    return res;
}

inline int qpow(int x,int y){
    if(x==2){
        if(y>=0) return p2[y];
        return inv[-y];
    }
    if(y>=0) return fpow(x,y);
    return fpow(fpow(x,-y),mod-2);
}

struct BIT{
    int tr[N];
    void add(int x,int k){
        for(;x0;x-=x&-x) (res+=tr[x])%=mod;
        return res;
    }
    void clear(){
        for(int i=1;i>c>>T;
    p2[0]=1,inv[0]=1;
    int inv2=fpow(2,mod-2);
    for(int i=1;i>n;
        num.clear(),bit.clear();
        for(int i=1;i>a[i],b[i]=a[i];
        sort(b+1,b+1+n);
        for(int i=1;ia[i]) ans=((ans+qpow(2,n-1)-swp)%mod+mod)%mod;
        }
        bit.add(a[2],qpow(2,2));
        num.add(a[2],1);
        for(int i=3;i
`#include
using namespace std;

#define int long long
const int N=2e5+5;
const int mod=998244353;
int c,T,n;
int a[N],b[N],p2[N],inv[N];

inline int fpow(int x,int y){
    int res=1;
    while(y){
        if(y&1) (res*=x)%=mod;
        (x*=x)%=mod,y>>=1;
    }
    return res;
}

inline int qpow(int x,int y){
    if(x==2){
        if(y>=0) return p2[y];
        return inv[-y];
    }
    if(y>=0) return fpow(x,y);
    return fpow(fpow(x,-y),mod-2);
}

struct BIT{
    int tr[N];
    void add(int x,int k){
        for(;xn;x+=x&-x) (tr[x]+=k)%=mod;
    }
    int get(int x){
        if(x0) return 0;
        int res=0;
        for(;x>0;x-=x&-x) (res+=tr[x])%=mod;
        return res;
    }
    void clear(){
        for(int i=1;in;i++) tr[i]=0;
    }
}bit,num;

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>c>>T;
    p2[0]=1,inv[0]=1;
    int inv2=fpow(2,mod-2);
    for(int i=1;iN;i++){
        p2[i]=(p2[i-1]*2)%mod;
        inv[i]=(inv[i-1]*inv2)%mod;
    }
    while(T--){
        int ans=0;
        cin>>n;
        num.clear(),bit.clear();
        for(int i=1;in;i++) cin>>a[i],b[i]=a[i];
        sort(b+1,b+1+n);
        for(int i=1;in;i++) a[i]=lower_bound(b+1,b+1+n,a[i])-b;
        if(n==1){
            cout"0\n";
            continue;
        }
        for(int i=2;in;i++){
            int swp=qpow(2,n-i);
            if(a[1]a[i]) (ans+=swp)%=mod;
            if(a[1]>a[i]) ans=((ans+qpow(2,n-1)-swp)%mod+mod)%mod;
        }
        bit.add(a[2],qpow(2,2));
        num.add(a[2],1);
        for(int i=3;in;i++){
            int sum=bit.get(n)-bit.get(a[i]),ni=num.get(n)-num.get(a[i]);
            ans=((ans-((qpow(2,n-2-i)*sum)%mod))%mod+mod)%mod;
            ans=(ans+((qpow(2,n-1)*ni)%mod))%mod;
            sum=bit.get(a[i]-1);
            ans=(ans+((qpow(2,n-2-i)*sum)%mod))%mod;
            bit.add(a[i],qpow(2,i));
            num.add(a[i],1);
        }
        coutans"\n";
    }
    return 0;
}`