NOI模拟18

T2 亿点整理

看到排列+矩阵就想行列式吧,当然前两天有一个是容斥

这个把\(f_{i,j}\)放到矩阵的指数上就可以实现乘法化,变成\(x^{f_{i,j}}\),这样我只要看\(x^{ik}\)有没有系数就行了

此时我们要求的是积和式,也就是行列式去掉-1的几次方,然而我们只需要判断有没有,那么就用行列式再rand个权值就行了

发现不能直接求多项式,所以用拉格朗日插值,并且我们让多项式指数mod k,用原根实现循环卷积就行了

多随机几个,卡个时,就可以出解了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=105;
int n,m,f[N][N],mod,g;
int ksm(int x,int y,int mo=mod){
    if(y<0)return 0;
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mo;
        x=x*x%mo;y>>=1;
    }return ret;
}
bool isp(int x){
    for(int i=2;i*i<=x;i++)if(x%i==0)return false;
    return true;
}
int ji[N],cj;
int findrt(){
    int ph=mod-1;
    for(int i=2;i*i<=ph;i++){
        if(ph%i==0)ji[++cj]=i;
        while(ph%i==0)ph/=i;
    }ph=mod-1;
    fo(i,2,mod){
        bool flag=true;
        fo(j,1,cj)if(ksm(i,ph/ji[j])==1){flag=false;break;}
        if(flag)return i;
    }return 0;
}
int a[N][N];
int gs(){
    int ret=1;
    fo(i,1,n){
        if(!a[i][i]){
            fo(j,i+1,n)if(a[j][i]){
                fo(k,i,n)swap(a[i][k],a[j][k]);
                ret=mod-ret;break;
            }
        }
        fo(j,i+1,n)if(a[j][i]){
            int t=a[j][i]*ksm(a[i][i],mod-2)%mod;
            fo(k,i,n)a[j][k]=(a[j][k]-a[i][k]*t%mod+mod)%mod;
        }
    }fo(i,1,n)ret=ret*a[i][i]%mod;
    return ret;
}
random_device you;
mt19937 pyt(20050223);
int rd(int l,int r){return uniform_int_distribution<>(l,r)(pyt);}
int x[N],y[N],rnd[N][N];
int get(){
    fo(i,1,n)fo(j,1,n){
        rnd[i][j]=rd(1,mod-1);
        // cerr<<rnd[i][j]<<endl;
    }
    fo(o,0,m-1){
        fo(i,1,n)fo(j,1,n)a[i][j]=rnd[i][j]*ksm(x[o],f[i][j])%mod;
        y[o]=gs();
    }int ret=0;
    fo(i,0,m-1){
        int fz=1,fm=1;
        fo(j,0,m-1)if(i!=j){
            fz=fz*(mod-x[j])%mod;
            fm=fm*(x[i]-x[j]+mod)%mod;
        }
        ret=(ret+fz*ksm(fm,mod-2)%mod*y[i])%mod;
    }return ret;
}
signed main(){
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
    n=read();m=read();
    fo(i,1,n)fo(j,1,n){
        f[i][j]=read();
    }
    for(mod=m*m+1;!isp(mod);mod+=m);
    g=findrt();
    // cerr<<mod<<" "<<g<<endl;
    x[0]=1;x[1]=ksm(g,(mod-1)/m);
    fo(i,2,m-1)x[i]=x[i-1]*x[1]%mod;
    while(1.0*clock()/CLOCKS_PER_SEC<1.5){
        if(get()){printf("Yes");return 0;}
    }printf("No");
    return 0;
}

T3 亿块田

吉司机线段树,神了!!

如果普通线段树不能维护,我们可以考虑对每次的修改找到一个临界值,一边是可以直接修改的,另一边是需要继续递归的

于是我们可以进行一个势能分析,然后找到正确的复杂度

这里就是利用了变换之后大小关系不变的原理,分析一下就行了!!

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=2e5+5;
int n,m,a[N],u;
struct XDS{
    #define ls x<<1
    #define rs x<<1|1
    int mx[N*4],ad[N*4],ar[N*4],td[N*4],tr[N*4];
    void pushup(int x){
        mx[x]=max(mx[ls],mx[rs]);
        ad[x]=ad[ls]&ad[rs];
        ar[x]=ar[ls]|ar[rs];
    }
    void pushd(int x,int v){
        mx[x]&=v;
        ad[x]&=v;ar[x]&=v;
        td[x]&=v;tr[x]&=v;
    }
    void pushr(int x,int v){
        mx[x]|=v;
        ad[x]|=v;ar[x]|=v;
        tr[x]|=v;
    }
    void pushdown(int x){
        if(td[x]!=u){pushd(ls,td[x]);pushd(rs,td[x]);td[x]=u;}
        if(tr[x]){pushr(ls,tr[x]);pushr(rs,tr[x]);tr[x]=0;}
    }
    void build(int x,int l,int r){
        td[x]=u;tr[x]=0;
        if(l==r)return ad[x]=ar[x]=mx[x]=a[l],void();
        int mid=l+r>>1;
        build(ls,l,mid);build(rs,mid+1,r);
        pushup(x);
    }
    void ins_td(int x,int l,int r,int ql,int qr,int v){
        if(ql<=l&&r<=qr){
            if((ad[x]&(u^v))==(ar[x]&(u^v))){
                pushd(x,v);return ;
            }
        }
        int mid=l+r>>1;pushdown(x);
        if(ql<=mid)ins_td(ls,l,mid,ql,qr,v);
        if(qr>mid)ins_td(rs,mid+1,r,ql,qr,v);
        pushup(x);
    }
    void ins_tr(int x,int l,int r,int ql,int qr,int v){
        if(ql<=l&&r<=qr){
            if((ad[x]&v)==(ar[x]&v)){
                pushr(x,v);return ;
            }
        }
        int mid=l+r>>1;pushdown(x);
        if(ql<=mid)ins_tr(ls,l,mid,ql,qr,v);
        if(qr>mid)ins_tr(rs,mid+1,r,ql,qr,v);
        pushup(x);
    }
    int qry(int x,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr)return mx[x];
        int mid=l+r>>1,ret=0;pushdown(x);
        if(ql<=mid)ret=max(ret,qry(ls,l,mid,ql,qr));
        if(qr>mid)ret=max(ret,qry(rs,mid+1,r,ql,qr));
        pushup(x);return ret;
    }
    #undef ls
    #undef rs
}xds;
signed main(){
    freopen("farm.in","r",stdin);
    freopen("farm.out","w",stdout);
    n=read();m=read();u=(1<<20)-1;
    fo(i,1,n)a[i]=read();
    xds.build(1,1,n);
    while(m--){
        int tp=read(),l=read(),r=read(),v;
        if(tp==1){v=read();xds.ins_td(1,1,n,l,r,v);}
        if(tp==2){v=read();xds.ins_tr(1,1,n,l,r,v);}
        if(tp==3){printf("%d\n",xds.qry(1,1,n,l,r));}
    }
    return 0;
}
posted @ 2022-06-08 14:42  fengwu2005  阅读(33)  评论(0编辑  收藏  举报