• soj考试2


    T1:子图

    给你一棵带点权的树,对于所有i∈[1,m],问树上是否存在连通子图的权值和=i?

    n<=3000,m<=100000。

    朴素的背包树形dp有nm的复杂度,bitset也无处优化。

    但是从根往叶子考虑,必经根的连通块权值和很好用bitset维护。每个点的bitset表示经过rt和该点子树及之前已访问点的连通块权值和可能值。类似树形dp的合并。

    树分治。时间复杂度O(n^2logn/w)

    //注意每次需要重新计算size,设置done标记。

    标程:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5    int x=0,f=1;char ch=getchar();
     6    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
     7    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
     8    return x*f;
     9 }
    10 const int N=3005;
    11 const int M=100005;
    12 struct node{int to,next;}num[N*2];
    13 int cnt,head[N],u,v,sz[N],Max[N],rt,n,m,Sz,w[N],done[N];
    14 bitset<M> bit[N],ans;
    15 void add(int x,int y)
    16 {num[++cnt].to=y;num[cnt].next=head[x];head[x]=cnt;}
    17 void find_rt(int x,int fa)
    18 {
    19     sz[x]=1;Max[x]=0;
    20     for (int i=head[x];i;i=num[i].next)
    21       if (num[i].to!=fa&&!done[num[i].to])
    22       {
    23             find_rt(num[i].to,x);
    24             sz[x]+=sz[num[i].to];
    25             Max[x]=max(Max[x],sz[num[i].to]);
    26       }
    27     Max[x]=max(Max[x],Sz-sz[x]);
    28     if (Max[x]<Max[rt]) rt=x;
    29 }
    30 void work(int x,int fa)
    31 {
    32     bit[x]=bit[fa]<<w[x];sz[x]=1;//sz需要重新计算 
    33     for (int i=head[x];i;i=num[i].next)
    34       if (num[i].to!=fa&&!done[num[i].to])
    35       {
    36             work(num[i].to,x);
    37             sz[x]+=sz[num[i].to];
    38             bit[x]|=bit[num[i].to];
    39       }
    40 }
    41 void solve(int u)
    42 {
    43     done[u]=1;work(u,0);ans|=bit[u];
    44     for (int i=head[u];i;i=num[i].next)
    45       if (!done[num[i].to])
    46       {
    47           rt=0;Sz=sz[num[i].to];
    48           find_rt(num[i].to,u);
    49           solve(rt);
    50         }
    51 }
    52 int main()
    53 {
    54     int T=read();
    55     bit[0][0]=1;
    56     while (T--)     
    57     {
    58         n=read();m=read();
    59        cnt=0;for (int i=1;i<=n;i++) bit[i].reset(),head[i]=done[i]=0;
    60        for (int i=1;i<n;i++) u=read(),v=read(),add(u,v),add(v,u);
    61        for (int i=1;i<=n;i++) w[i]=read();
    62        Max[0]=Sz=n;ans.reset();
    63        rt=0;find_rt(1,-1);
    64        solve(rt);
    65        for (int i=1;i<=m;i++) printf("%d",(int)ans[i]);
    66        puts("");
    67     }
    68    return 0;
    69 }

    T2:结婚

    一共有n户,每一户有ai个男孩和bi个女孩。n户的男孩总数=女孩总数。

    问男孩和女孩结成n对且没有一对是同户的方案数%998244353?n<=1e5。

    朴素dp:$dp[l+a-j-k]+=dp[l][i]*dbinom{a}{j}*dbinom{b}{j}*(gsum-bsum+l)^{underline{j}}*l^{underline{k}}$

    i为枚举到的住户。a,b为对应的男孩、女孩数。l表示当前还剩l个男孩未配对。每次都在前面找不冲突的女孩配对。j、k分别表示这一户的男孩、女孩配上对的数量。gsum表示之前的女孩总数,bsum表示之前的男孩总数。

    答案即为dp[0][n+1]。

    容斥,设g为至少有i对男女同户的方案数。Ans=sigma((-1)^i*g[i])。

    对每一户设置生成函数:F(i)=c0+c1*x+c2*x^2+...,x^i表示在这一户中选i对男女配对的方案数,组合数预处理。

    F(1)*F(2)*...*F(n)的第i项系数则是全局中选i对男女同户的方案数,*(n-i)!即为g[i]。

    分治fft加速O(nlog^2(n))。

    //写fft的时候尽量用pos[i]<i->swap(a[i],a[pos[i]])。

    //1<<l要大于原n,否则枚举时是0~n-1,最后一个算不到。

    标程:

     1 #include<bits/stdc++.h>
     2 #define P pair<int,int>
     3 #define fir first
     4 #define sec second
     5 using namespace std;
     6 typedef long long ll;
     7 const int mod=998244353;
     8 const int root=31;
     9 const int N=300005;
    10 int jc[N],inv[N],sum,ans,l,_n,w[N],pos[N],tmp[N],n,k1,k2,a,b,len[N],f[N],g[N];
    11 vector<int> vec[N];
    12 set<P> q;
    13 int read()
    14 {
    15    int x=0,f=1;char ch=getchar();
    16    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    17    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    18    return x*f;
    19 }
    20 int ksm(int x,int y)
    21 {
    22     int res=1;
    23     while (y) {if (y&1) res=(ll)res*x%mod; x=(ll)x*x%mod;y>>=1;}
    24     return res;
    25 }
    26 int c(int n,int m) {return (ll)jc[n]*inv[m]%mod*inv[n-m]%mod;}
    27 
    28 void init()
    29 {
    30     l=0;while ((1<<l)<=_n) l++;//1<<l必须要大于原来的n 
    31     _n=1<<l; int ww=ksm(root,1<<23-l);
    32     w[0]=1;
    33     for (int i=1;i<=_n;i++)
    34       w[i]=(ll)ww*w[i-1]%mod,pos[i]=((i&1)<<l-1)|(pos[i>>1]>>1);
    35 }
    36 void fft(int *a)
    37 {
    38     for (int i=0;i<_n;i++) if (pos[i]<i) swap(a[i],a[pos[i]]);//swap可以避免多用一个数组和慢得要死的memset 
    39    int len=1,id=_n;
    40     for (int i=0;i<l;i++)
    41     {
    42         int g=w[id>>=1];
    43         for (int j=0;j<_n;j+=2*len)
    44           for (int k=0,ww=1;k<len;k++)
    45           {
    46                int L=a[j+k],R=(ll)a[j+len+k]*ww%mod;
    47                a[j+k]=((ll)L+R)%mod;a[j+len+k]=((ll)L-R+mod)%mod;
    48                ww=(ll)ww*g%mod;
    49           }
    50         len<<=1;
    51     }
    52 }
    53 int main()
    54 {
    55     n=read();
    56     jc[0]=inv[0]=jc[1]=inv[1]=1;
    57     for (int i=2;i<=100000;i++) jc[i]=(ll)jc[i-1]*i%mod,inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
    58     for (int i=2;i<=100000;i++) inv[i]=(ll)inv[i-1]*inv[i]%mod;
    59     for (int i=1;i<=n;i++) 
    60     {
    61         a=read(),b=read();sum+=a;
    62         q.insert(P(len[i]=min(a,b)+1,i));
    63         for (int j=0;j<=min(a,b);j++)
    64           vec[i].push_back((ll)c(a,j)*c(b,j)%mod*jc[j]%mod);
    65     }    
    66     for (int i=1;i<n;i++)
    67     {
    68         k1=q.begin()->sec;q.erase(q.begin());
    69         k2=q.begin()->sec;q.erase(q.begin());
    70        memcpy(f,vec[k1].data(),len[k1]*4);
    71        memcpy(g,vec[k2].data(),len[k2]*4);
    72        vec[k1].clear();vec[k2].clear();
    73        
    74        _n=len[k1]+len[k2]-1;
    75        init();fft(f);fft(g);
    76        for (int j=0;j<_n;j++) f[j]=(ll)f[j]*g[j]%mod;
    77        fft(f);reverse(f+1,f+_n); int inv_n=ksm(_n,mod-2);
    78        for (int j=0;j<_n;j++) vec[k1].push_back((ll)f[j]*inv_n%mod),f[j]=g[j]=0;
    79         q.insert(P(len[k1]=_n,k1));
    80     }
    81     int u=q.begin()->sec;
    82     for (int i=0;i<=sum;i++)
    83     {
    84         int x=(ll)vec[u][i]*jc[sum-i]%mod;
    85         if (i&1) ans=((ll)ans-x+mod)%mod;else ans=((ll)ans+x)%mod;
    86     }
    87     printf("%d
    ",ans);
    88    return 0;
    89 }

    T3:构图

    给你两棵n个节点的树A,B。有一个m个点的图,一开始没有边。

    A和B上的每个节点都有一个信息ai,bi,表示取了这个点,就在图上ai-bi连边。

    对于1~n,询问取A树上和B树上1->i的路径上所有点的信息更新图,图中有多少个连通块?

    n,m<=1e4.

    对A树按深度分块。维护块顶到根路径的点信息扔进可退回并查集。

    每走一个块就对B树整体dfs,边走边处理点信息。如果B树中走到当前A树块中的点,那么暴力加入该点在A树中到块顶的链信息。

    时间复杂度O(n^1.5logn)。对于A树每个点最多暴力跳n^0.5,所有点就是O(n^1.5)。B树中在n^0.5个块中都跑一遍全树dfs,O(n^1.5)。并查集按秩合并logn。

    //注意分块的时候从底往上分块,若从上往下碰到扫把型会被卡掉。

    //注意判断dfs序。要在块端点子树内才会被该端点管辖。

    标程:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5    int x=0,f=1;char ch=getchar();
     6    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
     7    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
     8    return x*f;
     9 }
    10 const int N=10005;
    11 vector<int> vec_a[N],vec_b[N];
    12 int f[N],sz[N],top,tt,L,R,dep[N],Fa[N],n,ans[N],vis[N],u,v,au[N],av[N],bu[N],bv[N],Dfn,dfn[N],m;
    13 struct node{int x,y,sz,bf;}sta[N*2];
    14 int find(int x){return x==f[x]?x:find(f[x]);}
    15 void merge(int x,int y)
    16 {
    17     x=find(x);y=find(y);
    18     if (x==y) return;
    19     if (sz[x]>sz[y]) swap(x,y);
    20     sta[++top].x=x;sta[top].y=y;sta[top].sz=sz[y];sta[top].bf=f[x];
    21     f[x]=y;if (sz[x]==sz[y]) sz[y]++;
    22 }
    23 void Re(int x)
    24 {
    25     while (top>x)
    26     {
    27         f[sta[top].x]=sta[top].bf; 
    28         sz[sta[top].y]=sta[top].sz;
    29         top--;
    30     }
    31 }
    32 void work(int x)
    33 {
    34     int t=top;
    35     for (int i=x;i!=tt;i=Fa[i]) merge(au[i],av[i]);
    36     ans[x]=m-top;vis[x]=1;
    37     Re(t);
    38 }
    39 void dfs_B(int x,int fa)
    40 {
    41     int t=top;merge(bu[x],bv[x]);
    42     if (!vis[x]&&dfn[x]>=dfn[tt]) work(x);
    43     for (int i=0;i<vec_b[x].size();i++)
    44       if (vec_b[x][i]!=fa) dfs_B(vec_b[x][i],x);
    45     Re(t);
    46 }
    47 void dfs_A(int x,int fa)
    48 {
    49     int t=top; merge(au[x],av[x]);
    50     dep[x]=1;dfn[x]=++Dfn;
    51    for (int i=0;i<vec_a[x].size();i++)
    52      if (vec_a[x][i]!=fa) 
    53       {
    54            dfs_A(vec_a[x][i],x);
    55            dep[x]=max(dep[x],dep[vec_a[x][i]]+1);
    56       }
    57     if (dep[x]==100||x==1) tt=x,dfs_B(1,-1),dep[x]=0;
    58     Re(t);
    59 }
    60 int main()
    61 {
    62     int T=read();
    63     while (T--)
    64     {
    65         n=read();m=read();Dfn=top=0;
    66         for (int i=1;i<=n;i++) vec_a[i].clear(),vec_b[i].clear(),vis[i]=dfn[i]=0;
    67         for (int i=1;i<=n;i++) au[i]=read(),av[i]=read();
    68         for (int i=1;i<n;i++) u=read(),v=read(),vec_a[u].push_back(v),vec_a[v].push_back(u),Fa[v]=u;
    69         for (int i=1;i<=n;i++) bu[i]=read(),bv[i]=read();
    70         for (int i=1;i<n;i++) u=read(),v=read(),vec_b[u].push_back(v),vec_b[v].push_back(u);
    71         for (int i=1;i<=m;i++) f[i]=i,sz[i]=1;
    72         dfs_A(1,-1);
    73         for (int i=1;i<=n;i++) assert(vis[i]==1);
    74         for (int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    75     }
    76    return 0;
    77 }
  • 相关阅读:
    揭秘 HashMap 实现原理(Java 8)
    并发容器之写时拷贝的 List 和 Set
    Maven 整合 SSH 框架
    Hibernate框架学习之注解配置关系映射
    Hibernate框架学习之注解映射实体类
    单用户,多设备登录问题
    ios scrollview button 延时点击问题
    Android 的 AlarmManager 和 wakeLock联合使用
    ios bitcode 机制对 dsym 调试文件的影响
    信息类型的异步更新方法
  • 原文地址:https://www.cnblogs.com/Scx117/p/9098809.html
Copyright © 2020-2023  润新知