正睿集训每日总结【8.2】

啊~~好难啊,听得有点懵逼,
不过,比之前好多了/开心^ _ ^



动态规划例题选讲

Gcd Counting(Codeforces 990G)

【题目描述】
给出一颗 n n n 个节点的树,每个节点上有点权 a i a_i ai
现在要你求出满足以下条件的最长的树上路径
路径上经过节点 (包括两个端点) 点权的 G c d Gcd Gcd 和不等于 1 1 1
【数据范围】
n ⩽ 2 × 1 0 5 n\leqslant 2\times 10^5 n2×105
1 ⩽ a i ⩽ 2 × 1 0 5 1\leqslant a_i\leqslant 2\times 10^5 1ai2×105
【解析】
只要不互质就行了,因此我们不用具体考虑 G c d Gcd Gcd 的值,还不用考虑重复计算。
对于每个节点 u u u ,维护 D p [ u ] [ v ] Dp[u][v] Dp[u][v] 表示 u u u 往下挂出的点权都能被 v v v 整除的最长链。
v v v 只用取整除 a i a_i ai 的质数,个数很少,很容易转移,然后边转移边更新全局答案。
【核心代码】(盗个图)
在这里插入图片描述

You are given a tree(Codeforces 1039D)

【题目描述】
给出一颗 n n n 个节点的树,对于 1 ∼ n 1\sim n 1n 间的每一个数 k k k ,你需要求出:
最多能选出多少条互不相交的路径,每条路径的长度都为 k k k
【数据范围】
n ⩽ 1 0 5 n\leqslant 10^5 n105
【解析】
首先,我们先说一下贪心:在一个子树中,尽可能最大化完整的路径条数;其次最大化未完成的链的长度。
在进行合并时,先尝试儿子的 D p Dp Dp 值中第二维最大值与次大值能否拼成一条完整的链(长度和 ⩾ k \geqslant k k),若不行再选取一条最长的链向上延伸。时间复杂度: Θ ( n ) \Theta(n) Θ(n)
f [ k ] f[k] f[k] 表示单次对于给定的 k k k 的答案,那么显然有: f [ k ] ⩽ n k f[k]\leqslant\frac n k f[k]kn
T i p s : f \mathscr{Tips:f} Tips:f中不同的取值个数是 Θ ( n ) \Theta(\sqrt n) Θ(n ) 级别的。
f f f 显然是单调的,所以我们只要在每个边界上二分即可。
总时间复杂度: Θ ( n n log ⁡ n ) \Theta(n\sqrt n\log n) Θ(nn logn)

Vladislav and a Great Legend(Codeforces 1097G)

【题目描述】
给出一颗 n n n 个节点的树 T T T
对于其中任意一个非空节点集合 X X X ,定义 f ( X ) f(X) f(X) 为包含这些点的最小连通子树的边数。
给出一个正整数 k k k ,求: ∑ x ⊆ { 1 , 2 , … , n } , X ! = ∅ ( f ( X ) ) k \sum_{x\subseteq\{1,2,…,n\},X!=\empty}(f(X))^k x{1,2,,n},X!=(f(X))k答案对 1 0 9 + 7 10^9+7 109+7 取模。
【数据范围】
2 ⩽ n ⩽ 1 0 5 2\leqslant n\leqslant 10^5 2n105
1 ⩽ k ⩽ 200 1\leqslant k\leqslant 200 1k200
【解析】
( f ( X ) ) k (f(X))^k (f(X))k 很难直接算,于是我们把它拆开来: x k = ∑ i = 0 k ( x i ) × i ! × S ( k , i ) x^k=\sum_{i=0}^k\binom x i\times i!\times S(k,i) xk=i=0k(ix)×i!×S(k,i)其中 S ( k , i ) S(k,i) S(k,i) 是第二类斯特林数,表示将 k k k 个元素拆分成 i i i 个集合的方案数。

【第二类斯特林数算法核心代码】

Stirling[0][0]=1;
for(int i=1;i<=k;++i)
{
	for(int j=1;j<=i;++j)
	{
		Stirling[i][j]=(Stirling[i-1][j-1]+(ll)Stiring[i-1][j]*j%mod)%mod;
	}	
}

接下来我们把上式带回到原来题目里面的式子里去: A n s = ∑ X ∑ i = 0 k ( f ( X ) i ) × i ! × S ( k , i ) = ∑ i = 0 k i ! × S ( k , i ) ⋅ ∑ X ( f ( X ) i ) \begin{aligned} Ans&amp;=\sum_X\sum_{i=0}^k\binom{f(X)}i\times i!\times S(k,i)\\ &amp;=\sum_{i=0}^ki!\times S(k,i)\cdot\sum_X\binom{f(X)}i \end{aligned} Ans=Xi=0k(if(X))×i!×S(k,i)=i=0ki!×S(k,i)X(if(X))我们在外面枚举了 i i i 之后,要求的东西就是: 所 有 非 空 点 集 对 应 的 生 成 树 标 记 了 i 条 边 的 方 案 数 之 和 所有非空点集对应的生成树标记了i条边的方案数之和 i是不是看上去特别像树上背包,事实上树上背包也就够了。
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 i i i 为根的所有生成树当中标记了 j j j 条边的方案数,由于点集大小之类的不影响答案,所以不同点集对应的生成树可以一并考虑,得到: d p [ x ] [ i ] + = d p [ x ] [ j ] ∗ d p [ v ] [ i − j ] dp[x][i]+=dp[x][j]*dp[v][i-j] dp[x][i]+=dp[x][j]dp[v][ij]【代码展示】

#include<bits/stdc++.h>
#define ll long long
#define ud using namespace std
ud;
const int maxn=1e5+100;
const int mod=1e9+7; 
int n,k;
int top=0,first[maxn];
int mul[maxn],Size[maxn]={};
ll dp[maxn][210],g[210],s[210][210],f[maxn];
struct Tree
{
	int y;
	int next;
}e[maxn<<1];
void add(int x,int y)
{
	e[++top].y=y;
	e[top].next=first[x];
	first[x]=top;
}
ll jia(ll x,ll y)
{
	x+=y;
	if(x>=mod)
	x-=mod;
	return x;
} 
inline long long read()
{
	long long sum=0,flag=1;
	char c;
	for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
	for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
	return sum*flag;
}
void dfs(int x,int fa)
{
	Size[x]=1;
	dp[x][0]=2;
	for(int i=first[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y==fa)
		continue;
		dfs(y,x);
		memset(f,0,sizeof(f));
		for(int p=0;p<=min(Size[x],k);++p)
		{
			for(int q=0;q<=min(k-p,Size[y]);++q)
			{
				f[p+q]=jia(f[p+q],dp[x][p]*dp[y][q]%mod);
			}
		}
		
		for(int j=0;j<=k;++j)
		dp[x][j]=f[j];
		for(int j=0;j<=k;++j)
		g[j]=jia(g[j],mod-dp[y][j]);
		Size[x]+=Size[y];
	}
	for(int i=0;i<=k;++i)
	g[i]=jia(g[i],dp[x][i]);
	for(int i=k;i>=1;--i)
	dp[x][i]=jia(dp[x][i],dp[x][i-1]);
	dp[x][1]=jia(dp[x][1],mod-1);
}
int main()	
{
	n=read();
	k=read();
	mul[0]=1;
	for(int i=1;i<=k;++i)
	{
		mul[i]=(ll)mul[i-1]*i%mod;
	}
	s[0][0]=1;
	for(int i=1;i<=k;++i)
	{
		for(int j=1;j<=i;++j)
		{
			s[i][j]=jia(s[i-1][j-1],s[i-1][j]*j%mod);
		}
	}
	for(int i=1;i<n;++i)
	{
		int xx,yy;
		xx=read();
		yy=read();
		add(xx,yy);
		add(yy,xx); 
	}
	dfs(1,0);
	int ans=0;
	for(int i=0;i<=k;++i)
	ans=jia(ans,(ll)mul[i]*s[k][i]%mod*g[i]%mod);
	printf("%d\n",ans);
}

至于时间复杂度,看似是 Θ ( n k 2 ) \Theta(nk^2) Θ(nk2) ,实际是 Θ ( n k ) \Theta(nk) Θ(nk)
我们分三种情况考虑:
∙ s i z e [ u ] ⩾ k &amp; s i z e [ v ] ⩾ k , 单 次 合 并 复 杂 度 Θ ( k 2 ) \bullet size[u]\geqslant k\And size[v]\geqslant k,单次合并复杂度\Theta(k^2) size[u]k&size[v]k,Θ(k2)
此时每次相当于合并了两堆大小至少为 k k k 的石头,至多有 n k \frac n k kn 堆。
因此,合并次数为 Θ ( n k ) \Theta(\frac n k) Θ(kn) ,总复杂度 Θ ( n k ) \Theta(nk) Θ(nk)
∙ s i z e [ u ] ⩾ k &amp; s i z e [ v ] &lt; k , 单 次 合 并 复 杂 度 Θ ( k × s i z e [ v ] ) \bullet size[u]\geqslant k\And size[v]&lt;k,单次合并复杂度\Theta(k\times size[v]) size[u]k&size[v]<kΘ(k×size[v])
这种情况下 s i z e [ v ] size[v] size[v] 之和不超过 n n n ,因此总复杂度 Θ ( n k ) \Theta(nk) Θ(nk) u u u v v v 交换的情况也是如此。
∙ s i z e [ u ] &lt; k &amp; s i z e [ v ] &lt; k \bullet size[u]&lt;k\And size[v]&lt;k size[u]<k&size[v]<k
这相当于是正常的树上背包,树的大小为 Θ ( k ) \Theta(k) Θ(k) ,众所周知它的复杂度是 Θ ( k 2 ) \Theta(k^2) Θ(k2)
我们考虑每两个点之间的贡献只会产生在它们的 l c a lca lca 处最多有 n k \frac n k kn 棵这样的树,因此总复杂度 Θ ( n k ) \Theta(nk) Θ(nk)

综上可知,时间复杂度为 Θ ( n k ) \Theta(nk) Θ(nk)

Uniformly Branched Trees

【题目描述】
如果两棵树可以通过重标号后变为完全相同,那么它们就是 同构 的。
将中间节点定义为度数大于 1 1 1 的节点。
计算有 n n n 个节点,其中所有的中间节点度数都为 d d d 的互不同构的树的数量。
答案对大质数取模。
【数据范围】
1 ⩽ n ⩽ 1000 1\leqslant n\leqslant 1000 1n1000
2 ⩽ d ⩽ 10 2\leqslant d\leqslant 10 2d10
1 0 8 ⩽ m o d ⩽ 1 0 9 10^8\leqslant mod\leqslant 10^9 108mod109
【解析】

Multiplicity(Codeforces 1061C)

【题目描述】
有个长度为 n n n 的序列 a a a ,你需要统计 a a a 中有多少个棒棒的子序列。
一个序列 b b b 被定义为棒棒的,当且仅当: 对 于 序 列 中 每 一 个 位 置 i , b i 都 能 被 i 整 除 对于序列中每一个位置i,b_i都能被i整除 ibii答案对 1 0 9 + 7 10^9+7 109+7 取模。
【数据范围】
n ⩽ 1 0 5 n\leqslant 10^5 n105
1 ⩽ a i ⩽ 1 0 6 1\leqslant a_i\leqslant 10^6 1ai106
【解析】

Maximum Element(Codeforces 889C)

【题目描述】
有个神仙写了个序列求 m a x max max ,它长下面这样:
在这里插入图片描述
现在他比较关心的是出错的情况,请你算出有多少个 1 ∼ n 1\sim n 1n 的排列在这个函数的计算下答案不为 n n n
答案对 1 0 9 + 7 10^9+7 109+7 取模。
【数据范围】
n , k ⩽ 1 0 6 n,k\leqslant 10^6 n,k106
【解析】

Easy Problem(Codeforces 1096D)

【题目描述】
给出一个长度为 n n n 的字符串,如果这个字符串中含有子序列“ h a r d hard hard ”,那么这个字符串就很 h a r d hard hard 。你不希望这个字符串很 h a r d hard hard ,所以想要从中删掉几个字符使它不 h a r d hard hard
例: h a r d , h z a z r z d , h a a a a a r d hard,hzazrzd,haaaaard hard,hzazrzd,haaaaard 都很 h a r d hard hard ,而 h a r , h a r t , d r a h har,hart,drah har,hart,drah h a r d hard hard
删掉在原字符串中的第 i i i 个字符需要花费的代价为 a i a_i ai ,请求出最小代价
【数据范围】
1 ⩽ n ⩽ 1 0 5 1\leqslant n\leqslant 10^5 1n105
1 ⩽ a i ⩽ 998244353 1\leqslant a_i\leqslant 998244353 1ai998244353
【解析】

Kuro and Topological Parity(Codeforces 979E)

【题目描述】
有一个 n n n 个点的图,有一些点的颜色给定,另一些可以随意确定。另外,还可以在图上连一些从编号较小的节点向编号较大的节点的边。
对于一个确定的图,统计图中节点颜色黑白交错的路径条数,如果奇偶性 = p =p =p ,那么该图就被定义为好图。
请你求出好图的个数。
答案对 1 0 9 + 7 10^9+7 109+7 取模。
【数据范围】
1 ⩽ n ⩽ 50 1\leqslant n\leqslant 50 1n50
p ∈ { 0 , 1 } p\in\{0,1\} p{0,1}
【解析】

Hero Meet Devil(HDOJ 4899)

【题目描述】
给出一个字符串 S S S ,这个字符串只由 A , C , G , T A,C,G,T A,C,G,T 四个字母组成。
对于每个 1 ∼ ∣ S ∣ 1\sim|S| 1S 中的每一个 i i i ,求出满足以下条件的字符串 T T T 的个数:
1、长度为 m m m
2、只由 A , C , G , T A,C,G,T A,C,G,T 四个字母组成。
3、 L C S ( S , T ) = i LCS(S,T)=i LCS(S,T)=i .
答案对 1 0 9 + 7 10^9+7 109+7 取模。
【数据范围】
∣ S ∣ ⩽ 15 , m ⩽ 1000 |S|\leqslant 15,m\leqslant 1000 S15,m1000
【解析】

XHXJ’s LIS(HDOJ 4352)

【题目描述】
[ L , R ] [L,R] [L,R] 中,各位数字组成的序列的 L I S LIS LIS 恰好为 k k k 的数字个数。
【数据范围】
T ⩽ 1 0 4 , 0 &lt; L ⩽ R &lt; 2 63 − 1 T\leqslant 10^4,0&lt;L\leqslant R&lt;2^{63}-1 T104,0<LR<2631
1 ⩽ k ⩽ 10 1\leqslant k\leqslant 10 1k10
【解析】

Make It One(Codeforces 1043F)

【题目描述】
有一个长度为 n n n 的序列 a a a ,一个 a a a 中的子集被定义为好的当且仅当它其中元素的 G c d Gcd Gcd 1 1 1
求最小的好的子集的大小。
或判断不存在这样的子集。
【数据范围】
1 ⩽ n , a i ⩽ 3 × 1 0 5 1\leqslant n,a_i\leqslant3\times10^5 1n,ai3×105
【解析】

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值