胡测 8

人类迷惑行为之赛时人均 200。

冬日窗外的回忆原来是指《我好想做 APJifengc 老师的 b20 啊》的最后一段,好深刻。

天使玩偶/SJY摆烂

Kaguya 说 cdq 过不去我就直接冲根号了。

根号大体套路有若干,分块,根号分治,还有一个就是根号重构。发现总共不超过 \(100000\) 个点,那么根号个询问分一组,每组内的询问暴力查所有修改,然后每组处理完把所有的修改在原图上 bfs 一遍更新答案就行了。复杂度显然 \(O(n\sqrt n)\)

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
const int dx[]={1,-1,0,0,0,0},dy[]={0,0,1,-1,0,0},dz[]={0,0,0,0,1,-1};
int n,m,h,q;
bool check(int x,int y,int z){
    return x>=1&&x<=n&&y>=1&&y<=m&&z>=1&&z<=h;
}
struct node{
    int x,y,z;
};
int dis(node a,node b){
    return abs(a.x-b.x)+abs(a.y-b.y)+abs(a.z-b.z);
}
vector<node>tmp;
vector<vector<vector<int> > >ans;
void bfs(){
    queue<node>q;
    for(node x:tmp)q.push(x),ans[x.x][x.y][x.z]=0;
    tmp.clear();
    while(!q.empty()){
        node a=q.front();q.pop();
        int x=a.x,y=a.y,z=a.z;
        for(int i=0;i<6;i++){
            int xx=x+dx[i],yy=y+dy[i],zz=z+dz[i];
            if(check(xx,yy,zz)&&ans[xx][yy][zz]>ans[x][y][z]+1){
                ans[xx][yy][zz]=ans[x][y][z]+1;
                q.push({xx,yy,zz});
            }
        }
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&h,&q);
    ans.resize(n+1);
    for(int i=1;i<=n;i++){
        ans[i].resize(m+1);
        for(int j=1;j<=m;j++){
            ans[i][j].resize(h+1);
            for(int k=1;k<=h;k++)ans[i][j][k]=0x3f3f3f3f;
        }
    }
    int sq=sqrt(q);
    for(int i=1;i<=q;i++){
        int od,x,y,z;scanf("%d%d%d%d",&od,&x,&y,&z);
        if(od==1)tmp.push_back({x,y,z});
        else{
            int ret=ans[x][y][z];
            for(node a:tmp)ret=min(ret,dis(a,{x,y,z}));
            printf("%d\n",ret);
        }
        if(i%sq==0)bfs();
    }
    return 0;
}

Koishi的树

不是很能蚌的地方在于暴力跑的比正解快。

首先有个显然的 \(O(26nmq)\) 的 AC 自动机暴力。然后预处理每条边往上往下的转移矩阵,树剖矩阵乘一下就好了。

写了半天被卡空间了。然后他让我写平衡树?6。

不会平衡树,告辞。

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
const int mod=998244353;
int n,m,q;
char s[110];
struct gra{
    int v,next;
    string s;
}edge[20010];
int t,head[10010];
void add(int u,int v,char s[]){
    edge[++t].v=v;edge[t].next=head[u];head[u]=t;
    int len=strlen(s);
    for(int i=0;i<len;i++)edge[t].s+=s[i];
}
struct ACAM{
    int cnt,trie[110][26],fail[110];
    bool vis[110];
    void ins(char s[]){
        int p=0,len=strlen(s+1);
        for(int i=1;i<=len;i++){
            if(!trie[p][s[i]-'a'])trie[p][s[i]-'a']=++cnt;
            p=trie[p][s[i]-'a'];
        }
        vis[p]=true;
    }
    void build(){
        queue<int>q;
        for(int i=0;i<26;i++)if(trie[0][i])q.push(trie[0][i]);
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0;i<26;i++){
                if(trie[x][i]){
                    fail[trie[x][i]]=trie[fail[x]][i];
                    vis[trie[x][i]]|=vis[fail[trie[x][i]]];
                    q.push(trie[x][i]);
                }
                else trie[x][i]=trie[fail[x]][i];
            }
        }
    }
}ac;
int id[10010],cnt;
struct node{
    int a[40][40];
    node(){memset(a,0,sizeof(a));}
    node operator*(const node&s)const{
        node ret;
        for(int i=0;i<=cnt;i++){
            for(int j=0;j<=cnt;j++){
                for(int k=0;k<=cnt;k++){
                    ret.a[i][j]=(ret.a[i][j]+1ll*a[i][k]*s.a[k][j])%mod;
                }
            }
        }
        return ret;
    }
}faw[10010],up[10010],down[10010];
struct Vec{
    int a[40];
    Vec(){memset(a,0,sizeof(a));}
    Vec operator*(const node&s)const{
        Vec ret;
        for(int i=0;i<=cnt;i++){
            for(int j=0;j<=cnt;j++){
                ret.a[j]=(ret.a[j]+1ll*a[i]*s.a[i][j])%mod;
            }
        }
        return ret;
    }
};
int num,fa[10010],dep[10010],size[10010],son[10010],top[10010],dfn[10010],rk[10010];
void dfs1(int x,int f){
    dep[x]=dep[f]+1;fa[x]=f;size[x]=1;
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f){
            for(char c:edge[i].s){
                faw[edge[i].v].a[0][0]++;
                for(int j=0;j<=ac.cnt;j++){
                    if(id[j]){
                        int k=ac.trie[j][c-'a'];
                        faw[edge[i].v].a[id[j]][id[k]]++;
                    }
                }
            }
            dfs1(edge[i].v,x);
            size[x]+=size[edge[i].v];
            if(size[son[x]]<size[edge[i].v])son[x]=edge[i].v;
        }
    }
}
void dfs2(int x,int f,int tp){
    dfn[x]=++num;rk[num]=x;top[x]=tp;
    if(x==tp)up[x]=faw[x],down[x]=faw[x];
    else up[x]=faw[x]*up[fa[x]],down[x]=down[fa[x]]*faw[x];
    if(son[x])dfs2(son[x],x,tp);
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f&&edge[i].v!=son[x])dfs2(edge[i].v,x,edge[i].v);
    }
}
struct Tree{
    #define lson rt<<1
    #define rson rt<<1|1
    node val1,val2;
}tree[40010];
void pushup(int rt){
    tree[rt].val1=tree[lson].val1*tree[rson].val1;
    tree[rt].val2=tree[rson].val2*tree[lson].val2;
}
void build(int rt,int l,int r){
    if(l==r){
        tree[rt].val1=tree[rt].val2=faw[rk[l]];return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
    pushup(rt);
}
void query1(int rt,int L,int R,int l,int r,Vec &ans){
    if(l<=L&&R<=r){
        ans=ans*tree[rt].val1;return;
    }
    int mid=(L+R)>>1;
    if(l<=mid)query1(lson,L,mid,l,r,ans);
    if(mid<r)query1(rson,mid+1,R,l,r,ans);
}
void query2(int rt,int L,int R,int l,int r,Vec &ans){
    if(l<=L&&R<=r){
        ans=ans*tree[rt].val2;return;
    }
    int mid=(L+R)>>1;
    if(mid<r)query2(rson,mid+1,R,l,r,ans);
    if(l<=mid)query2(lson,L,mid,l,r,ans);
}
int query(int u,int v){
    Vec ans;ans.a[1]=1;
    vector<int>vec;
    while(top[u]!=top[v]){
        if(dep[top[u]]>dep[top[v]])ans=ans*up[u],u=fa[top[u]];
        else vec.push_back(v),v=fa[top[v]];
    }
    if(dep[u]<dep[v])query1(1,1,n,dfn[u]+1,dfn[v],ans);
    else query2(1,1,n,dfn[v]+1,dfn[u],ans);
    reverse(vec.begin(),vec.end());
    for(int x:vec)ans=ans*down[x];
    return ans.a[0];
}
int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d%s",&u,&v,s);
        add(u,v,s);add(v,u,s);
    }
    for(int i=1;i<=m;i++){
        scanf("%s",s+1);
        ac.ins(s);
    }
    ac.build();
    for(int i=0;i<=ac.cnt;i++){
        if(!ac.vis[i])id[i]=++cnt;
    }
    dfs1(1,0);dfs2(1,0,1);
    build(1,1,n);
    while(q--){
        int u,v;scanf("%d%d",&u,&v);
        printf("%d\n",query(u,v));
    }
    return 0;
}

APjifengc的Galgame

不是原神?不是原神?不是原神?

首先 \(dp_{x,i}\) 为到 \(x\),以 \(x\) 为根的子树的每条链选 \(i\) 个点的方案数。不难 \(O(n^2)\) dp。然后发现每个节点第二维的上限是最短的链长,于是可以搞一个形如短链剖分的东西。合并子树暴力合并,对于只有一个儿子的,相当于乘个 \(1+x\),打个标记在合并的时候 NTT 下放一下就行。

由于数据没有链,暴力可以冲过去。

为啥我 NTT 没预处理可以冲过随机数据。

/*不是原神?不是原神?不是原神?不是原神?不是原神?不是原神?不是原神?不是原神?不是原神?不是原神?不是原神?不是原神?不是原神?*/
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int mod=998244353;
typedef vector<int> poly;
int n,ans,wl,w[300010],jc[300010],inv[300010];
void get(int n){wl=1;while(wl<n)wl<<=1;}
#define add(x,y) (x+y>=mod?x+y-mod:x+y)
#define sub(x,y) (x<y?x-y+mod:x-y)
int qpow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=1ll*ans*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return ans;
}
void init(int n){
    int t=1;
    while((1<<t)<n)t++;
    t=min(t-1,21);
    w[0]=1;w[1<<t]=qpow(31,1<<21-t);jc[0]=inv[0]=inv[1]=1;
    for(int i=t;i>=1;i--)w[1<<i-1]=1ll*w[1<<i]*w[1<<i]%mod;
    for(int i=1;i<(1<<t);i++)w[i]=1ll*w[i&i-1]*w[i&-i]%mod;
    for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=1;i<=n;i++)inv[i]=1ll*inv[i-1]*inv[i]%mod,jc[i]=1ll*jc[i-1]*i%mod;
}
int C(int n,int m){
    return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
}
inline void DIF(poly &a){
    int n=a.size();
    for(int mid=n>>1;mid;mid>>=1){
        for(int i=0,k=0;i<n;i+=mid<<1,k++){
            for(int j=0;j<mid;j++){
                int x=a[i+j],y=1ll*a[i+j+mid]*w[k]%mod;
                a[i+j]=add(x,y);a[i+j+mid]=sub(x,y);
            }
        }
    }
}
inline void DIT(poly &a){
    int n=a.size();
    for(int mid=1;mid<n;mid<<=1){
        for(int i=0,k=0;i<n;i+=mid<<1,k++){
            for(int j=0;j<mid;j++){
                int x=a[i+j],y=a[i+j+mid];
                a[i+j]=add(x,y);a[i+j+mid]=1ll*sub(x,y)*w[k]%mod;
            }
        }
    }
    for(int i=1;i<=(n-1)>>1;i++)swap(a[i],a[n-i]);
    int inv=qpow(n,mod-2);
    for(int i=0;i<n;i++)a[i]=1ll*a[i]*inv%mod;
}
inline poly operator*(poly a,poly b){
    poly A(a),B(b);
    int n=A.size()+B.size();
    get(n);
    A.resize(wl);B.resize(wl);
    DIF(A);DIF(B);
    for(int i=0;i<wl;i++)A[i]=1ll*A[i]*B[i]%mod;
    DIT(A);A.resize(n-1);
    return A;
}
struct data{
    int k;
    poly v;
    void clear(){
        v.clear();v.shrink_to_fit();
    }
    void shik(){
        int s=v.size();
        if(k<=2*__lg(n)){
            for(int i=k;i>=1;i--){
                for(int j=s-1;j>=1;j--){
                    v[j]=(v[j]+v[j-1])%mod;
                }
            }
        }
        else{
            poly g(k+1);
            for(int i=0;i<=k;i++)g[i]=C(k,i);
            v=v*g;v.resize(s);
        }
        k=0;
    }
}dp[100010];
struct node{
    int v,next;
}edge[200010];
int t,head[100010];
void Add(int u,int v){
    edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
int len[100010],son[100010],cnt[100010];
void dfs1(int x,int f){
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f){
            dfs1(edge[i].v,x);
            cnt[x]++;
            if(!son[x]||len[son[x]]>len[edge[i].v])son[x]=edge[i].v;
        }
    }
    len[x]=len[son[x]]+1;
}
void dfs2(int x,int f){
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f){
            len[edge[i].v]=min(len[edge[i].v],len[x]);
            dfs2(edge[i].v,x);
        }
    }
}
void dfs(int x,int f){
    if(!son[x]){
        dp[x].v.resize(2);
        dp[x].v[0]=dp[x].v[1]=1;return;
    }
    dfs(son[x],x);
    if(cnt[x]==1){
        swap(dp[x].v,dp[son[x]].v);
        dp[x].v.resize(len[x]+1);dp[x].k=dp[son[x]].k+1;
        dp[son[x]].clear();
        return;
    }
    dp[x].v.resize(len[x]+1);
    dp[son[x]].shik();
    for(int i=0;i<=len[son[x]];i++)dp[x].v[i]=dp[son[x]].v[i];
    dp[son[x]].clear();
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f&&edge[i].v!=son[x]){
            dfs(edge[i].v,x);
            dp[edge[i].v].shik();
            for(int j=0;j<=len[edge[i].v];j++)dp[x].v[j]=1ll*dp[x].v[j]*dp[edge[i].v].v[j]%mod;
            dp[edge[i].v].clear();
        }
    }
    dp[x].k++;
}
int main(){
    scanf("%d",&n);init(n<<1);
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        Add(u,v);Add(v,u);
    }
    dfs1(1,0);dfs2(1,0);
    dfs(1,0);
    dp[1].shik();
    for(int i=0;i<=len[1];i++)ans=add(ans,dp[1].v[i]);
    printf("%d\n",ans);
    return 0;
}
posted @ 2023-04-26 16:04  gtm1514  阅读(14)  评论(0编辑  收藏  举报