2019/3/21模拟赛(构造,分治FFT,树套树)

题面

\(T1\)

解题思路

  硬核构造题,根据样例的提示。目前的思路就是让后手拿到\(K\),先手继续拿\(K-1\),后手继续拿\(K-2\),以此类推。那么可以这样构造:
  3 1 K-3 K-4 .. ..
  2 4 K-2 .. .. ..
  5 K K-1 .. .. Z
  Z-1 Z-2 ..

  那么这样的话先手刚开始会拿\(3\)后手拿\(2\),先手拿\(5\),后手拿\(K\),这样就到了上面的局面。\(n<=3\)需要特判一下。

代码

#include<bits/stdc++.h>
 
using namespace std;
const int N=1005;
 
int n,m,ans[N][N],xx[N*N],yy[N*N];
 
int main(){
    scanf("%d%d",&n,&m);
    int K=n*m;
    if(n==1){
        printf("3 2 1 ");
        for(int i=m;i>3;i--)
            printf("%d ",i);
        putchar('\n');
        for(int i=1;i<=m;i++)
            printf("1 %d\n",i);
        return 0;
    }
    if(n==2){
        ans[1][1]=3;
        ans[2][1]=2;
        ans[1][2]=1;
        ans[2][2]=K;
        K--;
        for(int i=1;i<=m-2;i++){
            if(i&1){
                for(int j=2;j;j--)
                    ans[j][i+2]=K,xx[K]=j,yy[K]=i+2,K--;
            }
            else {
                for(int j=1;j<=2;j++)
                    ans[j][i+2]=K,xx[K]=j,yy[K]=i+2,K--;
            }
        }
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=m;j++)
                printf("%d ",ans[i][j]);
            putchar('\n');
        }
        printf("1 1\n2 1\n2 2\n");
        for(int i=n*m-1;i>3;i--)
            printf("%d %d\n",xx[i],yy[i]);
        printf("1 2\n");
        return 0;
    }
    if(n==3 && m==3) {
        printf("6 1 3\n9 5 2\n8 7 4\n1 3\n2 3\n3 3\n3 2\n3 1\n2 1\n1 1\n2 2\n1 2\n");
        return 0;
    }
    if(n==3 && m==4){
        printf("3 2 4 7\n1 6 11 8\n5 10 12 9\n");
        printf("1 1\n1 2\n2 1\n2 2\n2 3\n3 3\n3 2\n3 4\n2 4\n1 4\n3 1\n1 3\n");
        return 0;
    }
    ans[1][1]=3; ans[1][2]=1; ans[2][1]=2;
    ans[2][2]=4; ans[3][1]=5; ans[3][2]=K;
    ans[1][3]=K-3; ans[2][3]=K-2; ans[3][3]=K-1;
    K-=4;
    for(int i=1;i<=m-3;i++){
        if(i&1) {
            for(int j=1;j<=3;j++)
                ans[j][i+3]=K,xx[K]=j,yy[K]=i+3,K--;
        }
        else {
            for(int j=3;j;j--)
                ans[j][i+3]=K,xx[K]=j,yy[K]=i+3,K--;
        }
    }
    for(int i=1;i<=n-3;i++){
        if(i&1) {
            for(int j=1;j<=m;j++)
                ans[i+3][j]=K,xx[K]=i+3,yy[K]=j,K--;
        }
        else {
            for(int j=m;j;j--)
                ans[i+3][j]=K,xx[K]=i+3,yy[K]=j,K--;
        }
    }
//  cerr<<K<<endl;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)
            printf("%d ",ans[i][j]);
        putchar('\n');
    }
    printf("1 1\n2 1\n3 1\n3 2\n3 3\n2 3\n1 3\n");
    for(int i=n*m-4;i>5;i--)
        printf("%d %d\n",xx[i],yy[i]);
    printf("2 2\n1 2\n");
    return 0;
}

  

T3

解题思路

  考场上犯了一个愚蠢到极点的有关宏定义的错误,导致炸成20。。这道题其实就是\(LUOGU4891\)。直接区间线段树套权值线段树即可,时空复杂度\(O(nlog^2n)\),需要离散化和垃圾回收卡空间。

代码

#pragma GCC optimize(3)
#pragma GCC optimize("Ofast","inline")
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
 
using namespace std;
const int N=100001;
const int M=N*350;
const int MOD=1e9+7;
 
inline int rd(){
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;
}
 
int n,Q,a[N],b[N],c[N],rt[270005],ans;
int bin[N*150],cur,cpy[N*3],num,u;
 
int fast_pow(int x,int y){
    int ret=1;
    for(;y;y>>=1){
        if(y&1) ret=1ll*ret*x%MOD;
        x=1ll*x*x%MOD;
    }
    return ret;
}
 
struct Ask{
    int op,x,y;
    Ask(int _op=0,int _x=0,int _y=0){
        op=_op; x=_x; y=_y;
    }
}ask[N];
 
struct Seg1{
    int ls[M],rs[M],tot,Mul[M],num[M];
    int newnode(){
        if(!cur) return ++tot;
        return bin[cur--];
    }
    void init(){
        for(int i=0;i<=M-5;i++)
            Mul[i]=1;
    }
    void update(int &x,int l,int r,int pos,int tp){
        if(!x) x=++tot;
        if(l==r) {
            if(tp){
                Mul[x]=1ll*Mul[x]*cpy[pos]%MOD;
                num[x]++;
            }
            else {
                Mul[x]=1ll*Mul[x]*fast_pow(cpy[pos],MOD-2)%MOD;
                num[x]--;
                if(!num[x]) bin[++cur]=x,x=0;
            }
            return;
        }
        if(pos<=mid) update(ls[x],l,mid,pos,tp);
        else update(rs[x],mid+1,r,pos,tp);
        Mul[x]=1ll*Mul[ls[x]]*Mul[rs[x]]%MOD;
        num[x]=num[ls[x]]+num[rs[x]];
        if(!num[x]) bin[++cur]=x,x=0;
    }
    int query(int x,int l,int r,int L,int R){
        if(Mul[x]==1) return 1;
        if(!x) return 1;
        if(L<=l && r<=R) return Mul[x];
        int ret=1;
        if(L<=mid) ret=1ll*ret*query(ls[x],l,mid,L,R)%MOD;
        if(mid<R) ret=1ll*ret*query(rs[x],mid+1,r,L,R)%MOD;
        return ret;
    }
    int query_num(int x,int l,int r,int L,int R){
        if(!x) return 0;
        if(!num[x]) return 0;
        if(L<=l && r<=R) return num[x];
        int ret=0;
        if(L<=mid) ret+=query_num(ls[x],l,mid,L,R);
        if(mid<R) ret+=query_num(rs[x],mid+1,r,L,R);
        return ret;
    }
}t1;
 
struct Seg2{
 
    void build(int x,int l,int r){
        for(int i=l;i<=r;i++) t1.update(rt[x],1,u,b[i],1);
        if(l==r) return;
        build(x<<1,l,mid); build(x<<1|1,mid+1,r);      
    }
    void update(int x,int l,int r,int pos,int k,int tp){
        t1.update(rt[x],1,u,k,tp);
        if(l==r) return;
        if(pos<=mid) update(x<<1,l,mid,pos,k,tp);
        else update(x<<1|1,mid+1,r,pos,k,tp);
    }
    int query(int x,int l,int r,int L,int R,int ll,int rr){
        if(L<=l && r<=R) return t1.query(rt[x],1,u,ll,rr);
        int ret=1;
        if(L<=mid) ret=1ll*ret*query(x<<1,l,mid,L,R,ll,rr)%MOD;
        if(mid<R) ret=1ll*ret*query(x<<1|1,mid+1,r,L,R,ll,rr)%MOD;
        return ret;
    }
    int query_num(int x,int l,int r,int L,int R,int ll,int rr){
        if(L<=l && r<=R) return t1.query_num(rt[x],1,u,ll,rr);
        int ret=0;
        if(L<=mid) ret+=query_num(x<<1,l,mid,L,R,ll,rr);
        if(mid<R) ret+=query_num(x<<1|1,mid+1,r,L,R,ll,rr);
        return ret;
    }  
}t2;
     
struct Seg3{
    int Max[270005],tag[270005];
    void pushdown(int x){
        Max[x<<1]=max(Max[x<<1],tag[x]);
        Max[x<<1|1]=max(Max[x<<1|1],tag[x]);
        tag[x<<1]=max(tag[x],tag[x<<1]);
        tag[x<<1|1]=max(tag[x],tag[x<<1|1]);
        tag[x]=0;
    }
    void build(int x,int l,int r){
        if(l==r) {Max[x]=c[l]; return;}
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        Max[x]=max(Max[x<<1],Max[x<<1|1]);
    }
    void update(int x,int l,int r,int L,int R,int k){
        if(L<=l && r<=R) {
            Max[x]=max(Max[x],k);
            tag[x]=max(tag[x],k);
            return;
        }
        if(tag[x]) pushdown(x);
        if(L<=mid) update(x<<1,l,mid,L,R,k);
        if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
        Max[x]=max(Max[x<<1],Max[x<<1|1]);
    }
    int query(int x,int l,int r,int pos){
        if(l==r) return Max[x];
        if(tag[x]) pushdown(x);
        if(pos<=mid) return query(x<<1,l,mid,pos);
        return query(x<<1|1,mid+1,r,pos);
    }
}t3;
 
int Div(int l,int r,int w){
    int ret;
    while(l<=r){
        if((t3.query(1,1,n,mid))==w) ret=mid,l=mid+1;
        else r=mid-1;
    }
    return ret;
}
 
int main(){
 
    n=rd(); Q=rd(); t1.init(); int op,x,y;
    for(int i=1;i<=n;i++) a[i]=rd(),cpy[++num]=a[i];
    for(int i=1;i<=n;i++) b[i]=rd(),cpy[++num]=b[i];
    //lsh
    for(int i=1;i<=Q;i++){
        op=rd(),x=rd(),y=rd();
        ask[i]=Ask(op,x,y);
        cpy[++num]=y;
    }
    sort(cpy+1,cpy+1+num);
    u=unique(cpy+1,cpy+1+num)-cpy-1;
 
    for(int i=1;i<=n;i++)
        b[i]=lower_bound(cpy+1,cpy+1+u,b[i])-cpy;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(cpy+1,cpy+1+u,a[i])-cpy;
    for(int i=1;i<=Q;i++)
        ask[i].y=lower_bound(cpy+1,cpy+1+u,ask[i].y)-cpy;
 
    for(int i=1;i<=n;i++) c[i]=max(a[i],c[i-1]);
    ans=1;
 
//  for(int i=1;i<=n;i++) cout<<c[i]<<" ";cout<<endl;
    for(int i=1;i<=n;i++) ans=1ll*ans*min(cpy[c[i]],cpy[b[i]])%MOD;
    t2.build(1,1,n); t3.build(1,1,n);
//  cerr<<t3.query(1,1,n,2)<<endl;
//  cerr<<t2.query_num(1,1,n,1,n,1,5)<<endl;
//  cerr<<ans<<endl;
    for(int i=1;i<=Q;i++){
        op=ask[i].op,x=ask[i].x,y=ask[i].y;
        if(op==1){
            t2.update(1,1,n,x,b[x],0);
            t2.update(1,1,n,x,y,1);
            int tmp=t3.query(1,1,n,x);
            if(tmp>b[x]) ans=1ll*ans*fast_pow(cpy[b[x]],MOD-2)%MOD;
            else ans=1ll*ans*fast_pow(cpy[tmp],MOD-2)%MOD;
            b[x]=y;
            if(tmp>b[x]) ans=1ll*ans*cpy[b[x]]%MOD;
            else ans=1ll*ans*cpy[tmp]%MOD;
        }
        else {
            int now=x,tmp,R,NUM,sum;
            while(now<=n){
                tmp=t3.query(1,1,n,now);
//              cerr<<tmp<<endl;
                if(tmp>=y) break;
//              cerr<<tmp<<endl;
                R=Div(now,n,tmp);
//              if(x==1) cout<<R<<endl;
//              cerr<<R<<endl;
//              if(x==2) cout<<tmp<<" "<<R<<endl;
                NUM=t2.query_num(1,1,n,now,R,tmp,y);
                int NUM2=t2.query_num(1,1,n,now,R,y+1,u);
                ans=1ll*ans*fast_pow(cpy[y],NUM2)%MOD;
                sum=t2.query(1,1,n,now,R,tmp,y);
                ans=1ll*ans*sum%MOD;
                ans=1ll*ans*fast_pow(fast_pow(cpy[tmp],MOD-2),NUM2+NUM)%MOD;
                now=R+1;
            }
//          cerr<<t3.query(1,1,n,4)<<endl;
            t3.update(1,1,n,x,n,y);
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2019-03-23 10:42  Monster_Qi  阅读(51)  评论(0编辑  收藏  举报