NOI模拟20220605

今天的题确实是难,我仅有50pts,被吊打了eeeeeeeeee

T1 求和

题面越简单,题目越难,这似乎是公认的道理了

但是这个可以找规律哦,直接对着杨辉三角搞就好了,然后就是一个crt

首先往回推一行,这样下指标变成连续的,发现可以对每一列的和进行递推,具体关系是\(2*f_i+f_{i+1}={n+1 \choose i+2}\)

于是这个可以在模奇数意义下求了,然后我们换个思路,从i+1推回i,发现后面2越来越多于是就不用算了

于是就CRT合并一下,就完事了!!!

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=1e6+50000;
int n,m,mod,ans;
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;
}
int p[N],cnt;bool vis[N];
void init(){
    int sq=sqrt(max(max(n,m),mod));
    fo(i,2,sq){
        if(!vis[i])p[++cnt]=i;
        for(int j=1;j<=cnt&&i*p[j]<=sq;j++){
            vis[i*p[j]]=true;
            if(i%p[j]==0)continue;
        }
    }
}
int pp[N],cc[N],cp;
int exgcd(int a,int b,int &x,int &y){
    if(!b)return x=1,y=0,a;
    int g=exgcd(b,a%b,x,y);
    int xx=x;x=y;y=xx-a/b*y;
    return g;
}
int inv(int x,int mo){
    // if(x==0)return 1;
    // return ksm(x,mod-2);
    int a,b;exgcd(x,mo,a,b);
    a=(a%mo+mo)%mo;return a;
}
int c[N],e[N];
int sol(int md){
    int nn,mm=m>>1<<1;if(n&1)nn=n;else nn=n+1;
    int now=md,ret=0;
    for(int i=1;i<=cnt&&p[i]*p[i]<=now;i++)if(now%p[i]==0){
        pp[++cp]=p[i];
        while(now%p[i]==0){
            now/=p[i];
            cc[cp]++;
        }
    }
    if(now!=1){pp[++cp]=now;cc[cp]=1;}
    fo(o,1,cp){
        int res=0;now=1;fo(i,1,cc[o])now*=pp[o];
        if(pp[o]!=2){
            // cerr<<o<<" "<<now<<endl;
            int ok=0,zh=nn,cc=0;
            while(zh&&zh%pp[o]==0)zh/=pp[o],cc++;
            ok=res=(nn-1>>1)%now;
            // cerr<<res<<" "<<ok<<" "<<now<<endl;
            fo(i,1,mm){
                // cerr<<i<<endl;
                int p1=nn-i,p2=i+1,c1=0,c2=0;
                while(p1&&p1%pp[o]==0)p1/=pp[o],c1++;
                while(p2&&p2%pp[o]==0)p2/=pp[o],c2++;
                cc+=c1-c2;
                // cerr<<p1<<" "<<p2<<endl;
                zh=zh*p1%now*inv(p2,now)%now;
                // cerr<<"SB"<<endl;
                ok=(zh*ksm(pp[o],cc,now)%now-ok+now)*inv(2,now)%now;
                res=(res+ok)%now;
                // cerr<<i<<endl;
            }
        }
        else {
            int t=cc[o];
            c[0]=1;e[0]=0;while(c[0]%2==0)c[0]/=2,e[0]++;
            // cerr<<c[0]<<endl;
            fo(i,1,min(nn,mm+t+2)){
                int p1=nn-i+1,p2=i,c1=0,c2=0;
                while(p1&&p1%2==0)p1/=2,c1++;
                while(p2&&p2%2==0)p2/=2,c2++;
                e[i]=e[i-1]+c1-c2;
                c[i]=c[i-1]*p1%now*inv(p2,now)%now;
                // cerr<<c[i]<<" ";
            }
            // cerr<<endl;
            // cerr<<m<<" "<<mm<<endl;
            fo(i,0,mm){
                // cerr<<i<<endl;
                int bas=1;
                fo(j,i+2,i+t+1){
                    // cerr<<i<<" "<<j<<" "<<nn<<" "<<c[j]<<" "<<e[j]<<" "<<res<<endl;
                    res=(res+bas*c[j]%now*ksm(2,e[j],now)%now+now)%now;
                    bas=bas*(-2);
                }
                // if(i==0)cerr<<res<<endl;
            }
        }
        // cerr<<res<<" "<<now<<endl;
        int x,y;exgcd(md/now,now,x,y);x=(x%now+now)%now;
        ret=(ret+x*md/now%md*res%md)%md;
    }
    return (ret+1)%md;
}
signed main(){
    n=read();m=min(n,read());mod=read();init();
    printf("%lld\n",sol(mod));
}

T2 农民

考场上一直在想平衡树,然后寄了,其实我们直接把每个点的限制写下来,发现是区间交

就可以发现其实是树剖线段树板子,至于子树翻转,直接再维护全翻转后的区间交就行了

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=1e5+5;
const int inf=0x3f3f3f3f;
struct node{
    int l,r;
    node(){l=0;r=inf;}
    node(int a,int b){l=a;r=b;}
    node operator + (node a)const{
        return node(max(l,a.l),min(r,a.r));
    }
};
struct XDS{
    #define ls x<<1
    #define rs x<<1|1
    node fi[N*4],se[N*4],nf[N*4],ns[N*4];
    bool tg[N*4];
    void pushup(int x){
        nf[x]=nf[ls]+nf[rs];
        ns[x]=ns[ls]+ns[rs];
    }
    void pushr(int x){
        swap(nf[x],ns[x]);
        tg[x]^=1;
    }
    void pushdown(int x){
        pushr(ls);pushr(rs);tg[x]=0;
    }
    void ins_vl(int x,int l,int r,int ps,int v,int tp){
        if(l==r){
            nf[x]=node(0,v-1);
            ns[x]=node(v+1,inf);
            if(tp)swap(nf[x],ns[x]);
            return ;
        }
        int mid=l+r>>1;if(tg[x])pushdown(x);
        if(ps<=mid)ins_vl(ls,l,mid,ps,v,tp);
        else ins_vl(rs,mid+1,r,ps,v,tp);
        pushup(x);
    }
    void ins_tg(int x,int l,int r,int ql,int qr){
        if(ql>qr)return ;
        if(ql<=l&&r<=qr)return pushr(x),void();
        int mid=l+r>>1;if(tg[x])pushdown(x);
        if(ql<=mid)ins_tg(ls,l,mid,ql,qr);
        if(qr>mid)ins_tg(rs,mid+1,r,ql,qr);
        pushup(x);
    }
    node qry(int x,int l,int r,int ql,int qr){
        if(ql>qr)return node();
        if(ql<=l&&r<=qr)return nf[x];
        int mid=l+r>>1;node ret;if(tg[x])pushdown(x);
        if(ql<=mid)ret=ret+qry(ls,l,mid,ql,qr);
        if(qr>mid)ret=ret+qry(rs,mid+1,r,ql,qr);
        pushup(x);return ret;
    }
    #undef ls
    #undef rs
}xds;
int n,m,ls[N],rs[N],fa[N],a[N],rt;bool vis[N];
int siz[N],son[N],dep[N],top[N];
int dfn[N],dfm[N],cnt,idf[N];
void dfs_fi(int x,int f){
    siz[x]=1;dep[x]=dep[f]+1;fa[x]=f;
    if(ls[x])dfs_fi(ls[x],x),siz[x]+=siz[ls[x]];
    if(rs[x])dfs_fi(rs[x],x),siz[x]+=siz[rs[x]];
    if(ls[x]&&rs[x])son[x]=siz[ls[x]]>siz[rs[x]]?ls[x]:rs[x];
    else son[x]=ls[x]+rs[x];
}
void dfs_se(int x,int f){
    top[x]=f;dfn[x]=++cnt;idf[cnt]=x;
    if(son[x])dfs_se(son[x],f);
    if(ls[x]&&ls[x]!=son[x])dfs_se(ls[x],ls[x]);
    if(rs[x]&&rs[x]!=son[x])dfs_se(rs[x],rs[x]);
    dfm[x]=cnt;
}
node qry(int x){
    node ret;
    while(x){
        // cerr<<ret.l<<" "<<ret.r<<" "<<dfn[top[x]]<<" "<<dfn[x]<<endl;
        ret=ret+xds.qry(1,1,n,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }return ret;
}
signed main(){
    n=read();m=read();
    fo(i,1,n){
        a[i]=read();ls[i]=read();rs[i]=read();
        vis[ls[i]]=vis[rs[i]]=true;
    }
    fo(i,1,n)if(!vis[i])rt=i;
    // cerr<<"SB"<<endl;
    dfs_fi(rt,0);dfs_se(rt,rt);
    // cerr<<"SB"<<endl;
    fo(i,1,n){
        if(ls[i])xds.ins_vl(1,1,n,dfn[ls[i]],a[i],0);
        if(rs[i])xds.ins_vl(1,1,n,dfn[rs[i]],a[i],1);
    }
    while(m--){
        int op=read(),x=read();
        if(op==1){
            a[x]=read();
            if((ls[x]&&xds.qry(1,1,n,dfn[ls[x]],dfn[ls[x]]).l==0)||(rs[x]&&xds.qry(1,1,n,dfn[rs[x]],dfn[rs[x]]).r==inf)){
                // cerr<<"SB"<<endl;
                if(ls[x])xds.ins_vl(1,1,n,dfn[ls[x]],a[x],0);
                if(rs[x])xds.ins_vl(1,1,n,dfn[rs[x]],a[x],1);
            }
            else {
                if(ls[x])xds.ins_vl(1,1,n,dfn[ls[x]],a[x],1);
                if(rs[x])xds.ins_vl(1,1,n,dfn[rs[x]],a[x],0);
            }
        }
        if(op==2){
            xds.ins_tg(1,1,n,dfn[x]+1,dfm[x]);
        }
        if(op==3){
            // cerr<<"SB"<<endl;
            node res=qry(x);
            // cerr<<res.l<<" "<<res.r<<" "<<xds.qry(1,1,n,dfn[1],dfn[1]).l<<endl;
            if(res.l<=a[x]&&a[x]<=res.r){
                printf("YES\n");
            }
            else printf("NO\n");
        }
    }
}

T3 仙人掌

这次认真的再次的写圆方树,似乎了解的更多了

没啥可说的,就用分治乘法优化一下背包而已

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=2e5+5;
const int mod=998244353;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,m,a[N],fd;
vector<int> d[N],e[N];
int dfn[N],low[N],cnt,sta[N],top;
vector<int> f[N];int dp[N][2],so[N],g[N];
bool cr[N];
void tarjan(int x,int fa){
    dfn[x]=low[x]=++cnt;
    sta[++top]=x;bool flag=true;
    for(int y:d[x]){
        if(y==fa&&flag){
            flag=false;
            continue;
        }
        if(!dfn[y]){
            tarjan(y,x);
            low[x]=min(low[x],low[y]);
            if(low[y]>=dfn[x]){
                ++fd;if(low[y]==dfn[x])cr[fd]=true;
                while(sta[top]!=y){
                    e[fd].push_back(sta[top]);
                    e[sta[top]].push_back(fd);
                    top--;
                }top--;
                e[fd].push_back(y);e[y].push_back(fd);
                e[fd].push_back(x);e[x].push_back(fd);
            }
        }
        else low[x]=min(low[x],dfn[y]);
    }
}
int af[1<<20],w[1<<20];
struct poly{
    vector<int> a;
    poly(){a.clear();}
    poly(int len){a.resize(len);}
    void ntt(int lim){
        fo(i,0,lim-1)if(af[i]>i)swap(a[i],a[af[i]]);
        for(int t=lim>>1,d=1;d<lim;d<<=1,t>>=1)
            for(int i=0;i<lim;i+=(d<<1))
                fo(j,0,d-1){
                    int tmp=a[i+j+d]*w[t*j]%mod;
                    a[i+j+d]=(a[i+j]-tmp+mod)%mod;
                    a[i+j]=(a[i+j]+tmp)%mod;
                }
    }
    poly operator * (poly x){
        int len=0,lim=1,l1=a.size(),l2=x.a.size();
        for(;lim<l1+l2;lim<<=1,len++);
        fo(i,0,lim-1)af[i]=(af[i>>1]>>1)|((i&1)<<(len-1));
        w[0]=1;w[1]=ksm(3,(mod-1)/lim);
        fo(i,2,lim-1)w[i]=w[i-1]*w[1]%mod;
        poly ret=poly(lim);
        while(a.size()<lim)a.push_back(0);
        while(x.a.size()<lim)x.a.push_back(0);
        ntt(lim);x.ntt(lim);
        fo(i,0,lim-1)ret.a[i]=a[i]*x.a[i];
        w[0]=1;w[1]=ksm(w[1],mod-2);
        fo(i,2,lim-1)w[i]=w[i-1]*w[1]%mod;
        ret.ntt(lim);int iv=ksm(lim,mod-2);
        fo(i,0,lim-1)ret.a[i]=ret.a[i]*iv%mod;
        while(ret.a.size()&&!ret.a.back())ret.a.pop_back();
        return ret;
    }
}p[N*4];int cp;
int sol(int l,int r){
    ++cp;
    if(r==0){
        p[cp].a.clear();p[cp].a.push_back(1);
        return cp;
    }
    if(l==r){
        p[cp]=poly(3);
        fo(i,0,2)p[cp].a[i]=f[so[l]][i];
        return cp;
    }
    int mid=l+r>>1;
    int ll=sol(l,mid),rr=sol(mid+1,r);
    p[cp]=p[ll]*p[rr];
    return cp;
}
void dfs_dp(int x,int fa){
    for(int y:e[x])if(y!=fa)dfs_dp(y,x);
    if(x>n){
        so[0]=0;
        for(int y:e[x])so[++so[0]]=y;
        if(!cr[x]){
            if(a[so[1]]>=1)f[x][0]=f[so[1]][a[so[1]]-1];
            f[x][1]=f[so[1]][a[so[1]]];
        }
        else {
            {
                fo(i,0,so[0])fo(j,0,1)dp[i][j]=0;
                dp[1][0]=1;
                fo(i,1,so[0]-1){
                    fo(j,0,1){
                        if(a[so[i]]>=j+1)dp[i+1][0]=(dp[i+1][0]+dp[i][j]*f[so[i]][a[so[i]]-j-1])%mod;
                        if(a[so[i]]>=j)dp[i+1][1]=(dp[i+1][1]+dp[i][j]*f[so[i]][a[so[i]]-j])%mod;
                    }
                }
                fo(i,0,min(1ll,a[fa]-1)){
                    f[x][i+1]=(f[x][i+1]+dp[so[0]][i])%mod;
                }
            }
            {
                fo(i,0,so[0])fo(j,0,1)dp[i][j]=0;
                dp[1][1]=1;
                fo(i,1,so[0]-1){
                    fo(j,0,1){
                        if(a[so[i]]>=j+1)dp[i+1][0]=(dp[i+1][0]+dp[i][j]*f[so[i]][a[so[i]]-j-1])%mod;
                        if(a[so[i]]>=j)dp[i+1][1]=(dp[i+1][1]+dp[i][j]*f[so[i]][a[so[i]]-j])%mod;
                    }
                }
                fo(i,0,min(1ll,a[fa])){
                    f[x][i]=(f[x][i]+dp[so[0]][i])%mod;
                }
            }
        }
    }
    else {
        so[0]=0;cp=0;
        for(int y:e[x])if(y!=fa)so[++so[0]]=y;
        // cerr<<so[0]<<" ";
        int ok=sol(1,so[0]),sz=p[ok].a.size();
        // cerr<<"ok"<<" "<<p[ok].a[0]<<endl;
        f[x][0]=(0>=sz?0:p[ok].a[0]);
        fo(i,1,a[x])f[x][i]=(f[x][i-1]+(i>=sz?0:p[ok].a[i]))%mod;
    }
    // cerr<<x<<endl;
    // fo(i,0,a[x])cerr<<f[x][i]<<" ";cerr<<endl;
}
signed main(){
    fd=n=read();m=read();
    fo(i,1,m){
        int x=read(),y=read();
        d[x].push_back(y);d[y].push_back(x);
    }
    fo(i,1,n)a[i]=min((int)d[i].size()+2,read()),f[i].resize(a[i]+1);
    tarjan(1,0);
    fo(i,n+1,fd)f[i].resize(3);
    dfs_dp(1,0);
    printf("%lld\n",f[1][a[1]]);
}
posted @ 2022-06-08 14:46  fengwu2005  阅读(32)  评论(0编辑  收藏  举报