NOI模拟14

好像是改完题了,也可以说是没改完,因为最后一个题letitdown的hack我过不了...

经过前两天的消沉,和思考,我明白了,执着于正解对我来说是没有意义的

所以今天就彻底躺平了心态,反而有一丝丝的进展,似乎,这才是属于我的策略吧

不能说波澜不惊,但是确实很平静

开场看了一遍题,这是我第一次用这样的策略,所以这时的心态也就不局限于T1了

先打的T3,认为暴力AC自动机是可以过掉的,然而数据出锅了,并且我的AC自动机写错了,终止节点忘记下传了

然后看的T2,看出来是二叉树的形态数,以为是卡特兰数,然而假了,于是就没有往那个方向想

最后写的T1,找到了结论,但是忘记了线性基求异或和是某一个数的方案数怎办了...

T1 奇怪的博弈

现在的SG函数题都有一个规律,就是大局面拆成小局面,这个也是一样的

白色的不用管,黑色的是有规律的,规律不说了

需要用到线性基求异或为某个值的方案数,如果线性基不能异或出来这个数,那就是0

如果可以的话,设S个不能插入到线性基的数,那么这些可以随便选,然后用线性基将其异或为0就行了,所以方案数是\(2^S\)

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=1e5+5;
const int mod=1e9+7;
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,a[N],ans;
struct BAS{
    int tr[65],sm,ok,ls;
    bool ins(int x){
        sm++;
        fu(i,60,0)if(x>>i&1){
            if(tr[i])x^=tr[i];
            else {
                tr[i]=x;ok++;
                return true;
            }
        }
        ls++;
        return false;
    }
    bool find(int x){
        fu(i,60,0)if(x>>i&1){
            if(tr[i])x^=tr[i];
            else return false;
        }if(!x)return true;
        return false;
    }
}bas;
int jc[N],inv[N];
int C(int x,int y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}
int pre[N],suf[N],pw2[N];
signed main(){
    freopen("nim.in","r",stdin);
    freopen("nim.out","w",stdout);
    n=read();
    fo(i,1,n)a[i]=read();
    sort(a+1,a+n+1);reverse(a+1,a+n+1);
    jc[0]=1;fo(i,1,n)jc[i]=jc[i-1]*i%mod;
    inv[0]=1;inv[n]=ksm(jc[n],mod-2);
    pw2[0]=1;fo(i,1,n)pw2[i]=pw2[i-1]*2%mod;
    fu(i,n-1,1)inv[i]=inv[i+1]*(i+1)%mod;
    fo(i,1,n)pre[i]=pre[i-1]^a[i];
    fu(i,n,1)suf[i]=suf[i+1]^a[i];
    int las=1;
    fo(i,1,n)if(a[i]!=a[i+1]){
        int sm=i-las+1;
        // cerr<<las<<" "<<i<<" "<<ans<<endl;
        fo(j,1,sm){
            int res=0;
            if(sm-j&1)res^=a[i];
            res^=suf[i+1];
            if(!(res^pre[las-1]^((j&1)?a[i]:a[i]-1)))ans=(ans+C(sm,j))%mod;
            res^=(a[i]-(j&1));
            if(bas.find(res)){
                // cerr<<res<<endl;
                ans=(ans+C(sm,j)*pw2[bas.ls])%mod;
                if(!(pre[las-1]^res)){
                    ans=(ans-C(sm,j)+mod)%mod;
                    // cerr<<"SB"<<endl;
                }
            }
        }
        fo(j,1,sm)bas.ins(a[i]);
        las=i+1;
    }
    // cerr<<ans<<endl;
    if(!pre[n])ans=(ans+1)%mod; 
    printf("%lld",ans);
    return 0;
}

T2 奇怪的划分

发现可以变成树形结构,我们可以用一个卷积形式的dp得到,不过这样是\(n^2\)的,如果使用分治ntt的话,可以做到两个log

我们可以讲这个卷积形式的东西写成\(EGF\),然后推一推,发现开根即可解决这个问题

这里有一个东西我竟然不知道,\(e^x\)用泰勒展开是\(\sum_{i>=0}\frac{x^i}{i!}\)

这里用到了这个东西,然后我们用求根公式得到封闭形式,这里舍根的话就看0处的点值是否合法就行了

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=1<<21;
const int mod=998244353;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=1ll*ret*x%mod;
        x=1ll*x*x%mod;y>>=1;
    }return ret;
}
int lim,len,af[N],w[N],iv2;
void ntt(int *a,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=1ll*w[t*j]*a[i+j+d]%mod;
                a[i+j+d]=(a[i+j]-tmp+mod)%mod;
                a[i+j]=(a[i+j]+tmp)%mod;
            }
}
int a[N],b[N],c[N];
void inv(int *x,int *y,int n){
    if(n==1)return y[0]=ksm(x[0],mod-2),void();
    inv(x,y,n+1>>1);
    for(lim=1,len=0;lim<2*n;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]=1ll*w[i-1]*w[1]%mod;
    fo(i,0,n-1)a[i]=x[i];//cerr<<x[i]<<" ";cerr<<endl;
    ntt(a,lim);ntt(y,lim);
    w[0]=1;w[1]=ksm(w[1],mod-2);
    fo(i,2,lim-1)w[i]=1ll*w[i-1]*w[1]%mod;
    fo(i,0,lim-1)y[i]=(2ll*y[i]-1ll*y[i]*y[i]%mod*a[i]%mod+mod)%mod;
    ntt(y,lim);int iv=ksm(lim,mod-2);
    fo(i,0,lim-1)y[i]=1ll*y[i]*iv%mod,a[i]=0;//cerr<<y[i]<<" ";cerr<<endl;
    fo(i,n,lim-1)y[i]=0;
}
void sqt(int *x,int *y,int n){
    if(n==1)return y[0]=1,void();
    sqt(x,y,n+1>>1);inv(y,c,n);
    for(lim=1,len=0;lim<2*n;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]=1ll*w[i-1]*w[1]%mod;
    fo(i,0,n-1)a[i]=x[i];
    fo(i,0,n-1)c[i]=1ll*c[i]*iv2%mod;
    ntt(a,lim);ntt(y,lim);ntt(c,lim);
    w[0]=1;w[1]=ksm(w[1],mod-2);
    fo(i,2,lim-1)w[i]=1ll*w[i-1]*w[1]%mod;
    fo(i,0,lim-1)y[i]=(a[i]+1ll*y[i]*y[i])%mod*c[i]%mod;
    ntt(y,lim);int iv=ksm(lim,mod-2);
    fo(i,0,lim-1)y[i]=1ll*y[i]*iv%mod,a[i]=c[i]=0;
    fo(i,n,lim-1)y[i]=0;
}
int T,n,q[N];
int jc[N],in[N],f[N],g[N];
signed main(){
    freopen("set.in","r",stdin);
    freopen("set.out","w",stdout);
    T=read();iv2=ksm(2,mod-2);
    fo(i,1,T)n=max(n,q[i]=read());
    jc[0]=1;fo(i,1,n)jc[i]=1ll*jc[i-1]*i%mod;
    in[0]=1;in[n]=ksm(jc[n],mod-2);
    fu(i,n-1,1)in[i]=1ll*in[i+1]*(i+1)%mod;
    f[0]=(3ll-2ll*in[0]%mod+mod)%mod;
    fo(i,1,n)f[i]=mod-2ll*in[i]%mod;
    // cerr<<f[0]<<" "<<f[1]<<" "<<f[2]<<" "<<f[3]<<endl;
    sqt(f,g,n+1);
    // cerr<<g[0]<<" "<<g[1]<<" "<<g[2]<<" "<<g[3]<<endl;
    fo(i,1,T)printf("%lld\n",(mod-1-1ll*g[q[i]]*jc[q[i]]%mod+mod)%mod);
}

T3 奇怪的植物

考场上写的暴力AC自动机,后来过了,后来又被卡了

been_hack_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=2505;
const int mod=998244353;
inline int mo(int x){return x>=mod?x-mod:x;}
int n,q,m,lns[N];
char s[N][30],t[50][50];
struct E{int to,nxt,id;}e[N*2];
int head[N],rp;
void add_edg(int x,int y,int id){
    e[++rp].to=y;e[rp].nxt=head[x];
    e[rp].id=id;head[x]=rp;
}
int fa[N],fe[N],dep[N];
void dfs(int x,int f){
    fa[x]=f;dep[x]=dep[f]+1;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==f)continue;
        fe[y]=e[i].id;dfs(y,x);
    }
}
int LCA(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    while(dep[x]>dep[y])x=fa[x];
    while(x!=y)x=fa[x],y=fa[y];
    return x;
}
struct AC{
    struct POT{int son[26],fail;bool ok;}tr[105];
    int seg;
    void ins(int id){
        int len=strlen(t[id]+1),now=0;
        fo(i,1,len){
            // cerr<<t[id][i];
            if(!tr[now].son[t[id][i]-'a'])tr[now].son[t[id][i]-'a']=++seg;
            now=tr[now].son[t[id][i]-'a'];
        }
        // cerr<<endl;
        tr[now].ok=true;
    }
    queue<int> q;
    void build(){
        // cerr<<seg<<endl;
        while(!q.empty())q.pop();
        fo(i,0,25)if(tr[0].son[i])q.push(tr[0].son[i]);
        while(!q.empty()){
            int x=q.front();q.pop();
            tr[x].ok|=tr[tr[x].fail].ok;
            fo(i,0,25){
                if(tr[x].son[i]){
                    tr[tr[x].son[i]].fail=tr[tr[x].fail].son[i];
                    q.push(tr[x].son[i]);
                }
                else tr[x].son[i]=tr[tr[x].fail].son[i];
            }
        }
    }
}ac;
int xl[N];
int dp[N][105],res[N],cnm[N],ans[5005];
vector<pair<int,int>> vec[N];
int siz[N];bool vis[N];
void dfs_fi(int x,int f){
    if(vis[x])siz[x]=1;else siz[x]=0;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==f)continue;
        dfs_fi(y,x);siz[x]+=siz[y];
    }
}
void dfs_dp(int x,int f){
    fo(j,0,ac.seg)res[x]=(res[x]+dp[x][j])%mod;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==f)continue;
        if(!siz[y])continue;
        fo(j,0,ac.seg)if(dp[x][j]){
            fo(k,1,lns[e[i].id]){
                int now=ac.tr[j].son[s[e[i].id][k]-'a'];
                if(ac.tr[now].ok)continue;
                dp[y][now]=(dp[y][now]+dp[x][j])%mod;
            }
        }
        cnm[y]=cnm[x]*lns[e[i].id]%mod;
        dfs_dp(y,x);
    }
}
void dfs_cl(int x,int f){
    if(siz[x]){
        res[x]=cnm[x]=0;
        fo(j,0,ac.seg)dp[x][j]=0;
    }
    else return ;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==f)continue;
        dfs_cl(y,x);
    }
}
signed main(){
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    n=read();m=read();q=read();
    fo(i,1,n-1){
        int x=read(),y=read();
        scanf("%s",s[i]+1);lns[i]=strlen(s[i]+1);
        if(!x||!y)continue;
        add_edg(x,y,i);add_edg(y,x,i);
    }
    dfs(1,0);
    fo(i,1,m)scanf("%s",t[i]+1),ac.ins(i);
    ac.build();
    fo(i,1,q){
        int u=read(),v=read();
        vec[u].push_back({v,i});
        // if(i==4148)cerr<<u<<" "<<v<<endl;
    }
    fo(u,1,n)if(vec[u].size()){
        if(u==1161)cerr<<vec[u].size()<<endl;
        for(pair<int,int> v:vec[u])vis[v.first]=true;
        dfs_fi(u,0);dp[u][0]=cnm[u]=1;dfs_dp(u,0);
        for(pair<int,int> v:vec[u])ans[v.second]=(cnm[v.first]-res[v.first]+mod)%mod;
        dfs_cl(u,0);dp[u][0]=cnm[u]=res[u]=0;
        for(pair<int,int> v:vec[u])vis[v.first]=false;
    }
    fo(i,1,q)printf("%lld\n",ans[i]);
    return 0;
}
posted @ 2022-05-24 19:57  fengwu2005  阅读(51)  评论(0编辑  收藏  举报