T1:子图

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

n<=3000,m<=100000。

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

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

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

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

标程:

 #include<bits/stdc++.h>
using namespace std;
int read()
{
int x=,f=;char ch=getchar();
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') x=(x<<)+(x<<)+ch-'',ch=getchar();
return x*f;
}
const int N=;
const int M=;
struct node{int to,next;}num[N*];
int cnt,head[N],u,v,sz[N],Max[N],rt,n,m,Sz,w[N],done[N];
bitset<M> bit[N],ans;
void add(int x,int y)
{num[++cnt].to=y;num[cnt].next=head[x];head[x]=cnt;}
void find_rt(int x,int fa)
{
sz[x]=;Max[x]=;
for (int i=head[x];i;i=num[i].next)
if (num[i].to!=fa&&!done[num[i].to])
{
find_rt(num[i].to,x);
sz[x]+=sz[num[i].to];
Max[x]=max(Max[x],sz[num[i].to]);
}
Max[x]=max(Max[x],Sz-sz[x]);
if (Max[x]<Max[rt]) rt=x;
}
void work(int x,int fa)
{
bit[x]=bit[fa]<<w[x];sz[x]=;//sz需要重新计算
for (int i=head[x];i;i=num[i].next)
if (num[i].to!=fa&&!done[num[i].to])
{
work(num[i].to,x);
sz[x]+=sz[num[i].to];
bit[x]|=bit[num[i].to];
}
}
void solve(int u)
{
done[u]=;work(u,);ans|=bit[u];
for (int i=head[u];i;i=num[i].next)
if (!done[num[i].to])
{
rt=;Sz=sz[num[i].to];
find_rt(num[i].to,u);
solve(rt);
}
}
int main()
{
int T=read();
bit[][]=;
while (T--)
{
n=read();m=read();
cnt=;for (int i=;i<=n;i++) bit[i].reset(),head[i]=done[i]=;
for (int i=;i<n;i++) u=read(),v=read(),add(u,v),add(v,u);
for (int i=;i<=n;i++) w[i]=read();
Max[]=Sz=n;ans.reset();
rt=;find_rt(,-);
solve(rt);
for (int i=;i<=m;i++) printf("%d",(int)ans[i]);
puts("");
}
return ;
}

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,最后一个算不到。

标程:

 #include<bits/stdc++.h>
#define P pair<int,int>
#define fir first
#define sec second
using namespace std;
typedef long long ll;
const int mod=;
const int root=;
const int N=;
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];
vector<int> vec[N];
set<P> q;
int read()
{
int x=,f=;char ch=getchar();
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') x=(x<<)+(x<<)+ch-'',ch=getchar();
return x*f;
}
int ksm(int x,int y)
{
int res=;
while (y) {if (y&) res=(ll)res*x%mod; x=(ll)x*x%mod;y>>=;}
return res;
}
int c(int n,int m) {return (ll)jc[n]*inv[m]%mod*inv[n-m]%mod;} void init()
{
l=;while ((<<l)<=_n) l++;//1<<l必须要大于原来的n
_n=<<l; int ww=ksm(root,<<-l);
w[]=;
for (int i=;i<=_n;i++)
w[i]=(ll)ww*w[i-]%mod,pos[i]=((i&)<<l-)|(pos[i>>]>>);
}
void fft(int *a)
{
for (int i=;i<_n;i++) if (pos[i]<i) swap(a[i],a[pos[i]]);//swap可以避免多用一个数组和慢得要死的memset
int len=,id=_n;
for (int i=;i<l;i++)
{
int g=w[id>>=];
for (int j=;j<_n;j+=*len)
for (int k=,ww=;k<len;k++)
{
int L=a[j+k],R=(ll)a[j+len+k]*ww%mod;
a[j+k]=((ll)L+R)%mod;a[j+len+k]=((ll)L-R+mod)%mod;
ww=(ll)ww*g%mod;
}
len<<=;
}
}
int main()
{
n=read();
jc[]=inv[]=jc[]=inv[]=;
for (int i=;i<=;i++) jc[i]=(ll)jc[i-]*i%mod,inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
for (int i=;i<=;i++) inv[i]=(ll)inv[i-]*inv[i]%mod;
for (int i=;i<=n;i++)
{
a=read(),b=read();sum+=a;
q.insert(P(len[i]=min(a,b)+,i));
for (int j=;j<=min(a,b);j++)
vec[i].push_back((ll)c(a,j)*c(b,j)%mod*jc[j]%mod);
}
for (int i=;i<n;i++)
{
k1=q.begin()->sec;q.erase(q.begin());
k2=q.begin()->sec;q.erase(q.begin());
memcpy(f,vec[k1].data(),len[k1]*);
memcpy(g,vec[k2].data(),len[k2]*);
vec[k1].clear();vec[k2].clear(); _n=len[k1]+len[k2]-;
init();fft(f);fft(g);
for (int j=;j<_n;j++) f[j]=(ll)f[j]*g[j]%mod;
fft(f);reverse(f+,f+_n); int inv_n=ksm(_n,mod-);
for (int j=;j<_n;j++) vec[k1].push_back((ll)f[j]*inv_n%mod),f[j]=g[j]=;
q.insert(P(len[k1]=_n,k1));
}
int u=q.begin()->sec;
for (int i=;i<=sum;i++)
{
int x=(ll)vec[u][i]*jc[sum-i]%mod;
if (i&) ans=((ll)ans-x+mod)%mod;else ans=((ll)ans+x)%mod;
}
printf("%d\n",ans);
return ;
}

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序。要在块端点子树内才会被该端点管辖。

标程:

 #include<bits/stdc++.h>
using namespace std;
int read()
{
int x=,f=;char ch=getchar();
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') x=(x<<)+(x<<)+ch-'',ch=getchar();
return x*f;
}
const int N=;
vector<int> vec_a[N],vec_b[N];
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;
struct node{int x,y,sz,bf;}sta[N*];
int find(int x){return x==f[x]?x:find(f[x]);}
void merge(int x,int y)
{
x=find(x);y=find(y);
if (x==y) return;
if (sz[x]>sz[y]) swap(x,y);
sta[++top].x=x;sta[top].y=y;sta[top].sz=sz[y];sta[top].bf=f[x];
f[x]=y;if (sz[x]==sz[y]) sz[y]++;
}
void Re(int x)
{
while (top>x)
{
f[sta[top].x]=sta[top].bf;
sz[sta[top].y]=sta[top].sz;
top--;
}
}
void work(int x)
{
int t=top;
for (int i=x;i!=tt;i=Fa[i]) merge(au[i],av[i]);
ans[x]=m-top;vis[x]=;
Re(t);
}
void dfs_B(int x,int fa)
{
int t=top;merge(bu[x],bv[x]);
if (!vis[x]&&dfn[x]>=dfn[tt]) work(x);
for (int i=;i<vec_b[x].size();i++)
if (vec_b[x][i]!=fa) dfs_B(vec_b[x][i],x);
Re(t);
}
void dfs_A(int x,int fa)
{
int t=top; merge(au[x],av[x]);
dep[x]=;dfn[x]=++Dfn;
for (int i=;i<vec_a[x].size();i++)
if (vec_a[x][i]!=fa)
{
dfs_A(vec_a[x][i],x);
dep[x]=max(dep[x],dep[vec_a[x][i]]+);
}
if (dep[x]==||x==) tt=x,dfs_B(,-),dep[x]=;
Re(t);
}
int main()
{
int T=read();
while (T--)
{
n=read();m=read();Dfn=top=;
for (int i=;i<=n;i++) vec_a[i].clear(),vec_b[i].clear(),vis[i]=dfn[i]=;
for (int i=;i<=n;i++) au[i]=read(),av[i]=read();
for (int i=;i<n;i++) u=read(),v=read(),vec_a[u].push_back(v),vec_a[v].push_back(u),Fa[v]=u;
for (int i=;i<=n;i++) bu[i]=read(),bv[i]=read();
for (int i=;i<n;i++) u=read(),v=read(),vec_b[u].push_back(v),vec_b[v].push_back(u);
for (int i=;i<=m;i++) f[i]=i,sz[i]=;
dfs_A(,-);
for (int i=;i<=n;i++) assert(vis[i]==);
for (int i=;i<=n;i++) printf("%d\n",ans[i]);
}
return ;
}

soj考试2的更多相关文章

  1. [SOJ #721]第三送分题(2019-11-14考试)/[CF675E]Trains and Statistic

    题目大意 在一条直线上有\(n\)个点.在第\(i\)个点可以花费\(1\)的代价到达\((i,a_i]\)中任意一点,用\(S[i][j]\)表示从点\(i\)到点\(j\)的最少花费,求\(\su ...

  2. [SOJ #696]染色(2019-11-10考试)/[Atcoder MUJIN Programming Challenge C]Orange Graph

    题目大意 有一个\(n\)个点\(m\)条边的简单无向连通图,初始为白色,可以执行操作让一些边变黑,要求使得操作后的图不存在黑色的奇环,且不能使得其他的任何变黑而还符合要求.问最后有多少可能结果.\( ...

  3. [SOJ #687]双生串(2019-11-6考试)/[hdu5431]AB String

    题目大意 把所有仅包含\(AB\)的字符串按字典序排列,给你一个仅包含\(AB\)的字符串\(S\),然后有\(Q\)个问题,第\(i\)个问题给你\(k_i\),求不是\(S\)的子串中,第\(k_ ...

  4. [SOJ #686]抢救(2019-11-7考试)/[洛谷P3625][APIO2009]采油区域

    题目大意 有一个\(n\times m\)的网格,\((x,y)\)权值为\(a_{x,y}\),要求从中选取三个不相交的\(k\times k\)的正方形使得它们权值最大.\(n,m,k\leqsl ...

  5. [SOJ #498]隔膜(2019-10-30考试)/[POJ2152]Fire

    题目大意:有一棵$n$个点的带边权树,第$i$个点有两个值$w_i,d_i$,表示在这个点做标记的代价为$w_i$,且这个点距离$d_i$以内至少要有一个点被标记,为最小代价.$n\leqslant6 ...

  6. [SOJ #537]不包含 [CF102129I]Incomparable Pairs(2019-8-6考试)

    题目大意:给定一个长度为$n$的字符串$s$,求有多少个无序字符串二元组$(x,y)$满足:$x,y$是$s$的字串,且$x$不是$y$的字串,$y$不是$x$的字串 题解:发现满足$x,y$是$s$ ...

  7. [SOJ #538]好数 [CC]FAVNUM(2019-8-6考试)

    题目大意:给定$n$个正整数,求$[l,r]$中第$k$小的”好数“.$l,r\leqslant10^{18},n\leqslant62$,出现的其他数均$\leqslant10^{50}$ 好数定义 ...

  8. 全网独家MongoDB Certified DBA Associate考试认证视频

    该视频意在让所有学员一次通过考试,避免重复考试而承担的巨额考试费用! 目前MongDB发展迅猛,有赶超mysql,和oracle看齐的苗头.在这个时候MongoDB也适时的推出了官方的认证考试&quo ...

  9. 记lrd的高二上学期第五次调研考试

    河北某某中学的调研考试其实是很好玩的经历呢.可惜没有太多机会了. 背景: NOIP2016回来之后没有好好学文化课-.自习能翘就翘了,衡中特产学案自助没有好好写(说来我好像从来没被老师查到过,上课写学 ...

随机推荐

  1. Nginx学习——proxy_pass

    参考官网:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass 定义:用来设置被代理服务器的协议(http或https ...

  2. Spring Boot整合Thymeleaf模板引擎

    什么是Thymeleaf Thymeleaf是一款用于渲染XML.XHTML.HTML5内容的模板引擎.类似Velocity,FreeMaker模板引擎,它也可以轻易的与Spring MVC等Web框 ...

  3. 净心诀---python3生成器

    生成器的作用----减少程序运行的内存开销 生成器特点: 1.一个一个的取值,而不是一次性把所有数据创建出来,迭代器中的数据不取不创建2.只能按照顺序取,不能跳过也不能回头3.一个迭代器中的数据只能从 ...

  4. swagger使用详解

    1:认识Swagger Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法 ...

  5. js中的Array数组清空

    var data = new Array();//数组 data.length = 0;//数组的长度等于0,数组的项就会被清空

  6. linux redis的启动---后台启动

    1.启动redis服务: redis-server 如果想要开启后台进程: 1.找到redis.conf里边的 把no 改为yes. 2.redis-server redis.conf(这个是针对两个 ...

  7. ajax-jq

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. Jmeter-【JSON Extractor】-响应结果中一级key取值

    一.请求返回样式 二.取code值 三.查看结果

  9. swiper缩略图active切换失灵的解决思路

    报错信息:Cannot read property ‘indexOf’ of undefined swiper. 来源是swiper.min.js,首先检查自己写的js配置是否有误,没有就调试插件源代 ...

  10. grep命令 一 文本搜索工具

    使用正则表达式搜索文本,并把匹配的行打印出来.使用权限是所有用户. 基本使用 grep [option] pattern filename: pattern如果是表达式或者超过两个单词的, 需要用引号 ...