首页 > 其他分享 >P10717 题解

P10717 题解

时间:2024-07-25 12:29:08浏览次数:12  
标签:P10717 状态 int 题解 复杂度 k4 转移 rightarrow

好神仙的题目。赛时胡了一个状态和转移都和官解不同的做法,得到了 \(O(n10^m)\) 的优秀复杂度。卡了一场常卡进了 \(75\) 分。这个做法和官解关系不大,并且很难进行最后的优化部分,所以在此不再赘述。

首先考虑 \(k=1\) 的情况。考虑记录一些状态能够描述子树内的选择方案,\(0\) 表示整个子树没有被覆盖过,\(1\) 表示子树内部有点被覆盖过并且子树外的点还能被覆盖,\(2\) 表示子树内部有点被覆盖过并且子树外的点不能被覆盖了。考虑转移,需要把转移描述为只和 \(u,v\) 有关的形式才能较为简单的扩展到 \(k\neq 1\) 的情况。发现对于 \(1\rightarrow 2\) 的转移,很难描述为 \(u,v\) 的形式,因为需要出现两个子树为 \(1\) 或者根节点被选择才能转移到 \(2\)。所以考虑记录辅助状态 \(3\) 表示出现过至少 \(2\) 次 \(1\) 的方案。那么转移有以下 \(8\) 种:

\[(0,0)\rightarrow 0 \]

\[(0,1)\rightarrow 1 \ \ (1,0)\rightarrow 1 \]

\[(0,2)\rightarrow 2 \ \ (2,0)\rightarrow 2 \]

\[(3,0)\rightarrow 3 \ \ (3,1)\rightarrow 3 \]

\[(1,1)\rightarrow 3 \]

上面没有出现过的转移为不合法或者不存在对应状态。这么转移之后再考虑和根节点是否选择合并的转移,那么有:

\[(0,0)\rightarrow 0 \ \ (1,0)\rightarrow 1 \ \ (2,0)\rightarrow 2 \ \ (3,0)\rightarrow 3 \ \ \]

\[(0,1)\rightarrow 3 \ \ (1,1)\rightarrow3 \ \ (3,1)\rightarrow 3 \ \ \]

转移的同时计入 \(p,a\) 两个数组的贡献。最后将 \(3\) 状态放到 \(1,2\) 两种状态即可。因为 \(3\) 状态对应的状态可以封口也可以不封口。复杂度 \(O(n)\)。

考虑对于 \(k\neq 1\) 的情况,每一位暴力枚举上面的 \(8\) 种转移,第一部分的转移复杂度是 \(O(8^k)\) 的。对于复合根节点情况的部分,暴力枚举根节点状态显然不优,可以类似 FMT 的对每一位依次进行变换,也就是逐位枚举根节点状态并处理这一位变换后的位置。复杂度为 \(O(k4^k)\)。对于 \(3\) 状态的下放可以用类似的做法也做到 \(O(k4^k)\)。复杂度 \(O(n(8^k+k4^k))\),视常数可以获得 \(45\sim 85\) 分。

考虑优化,目前的瓶颈在于 \(O(8^k)\) 的部分。一个很神秘的做法是考虑到如果没有辅助状态 \(3\),那么转移只有 \(O(5^k)\)。所以考虑枚举儿子的一些位置的状态钦定为 \(3\),由于对于 \(3\) 的转移是和 \(0/1\) 复合之后仍然为 \(3\),所以为 \(3\) 的位可以让它的值为对应位为 \(0/1\) 的和。类似 OR 卷积的 FWT,经过一次正变换之后为 \(3\) 的位置真实值可以为 \(0\) 或 \(1\)。然后对变换之后的部分进行 \(O(5^k)\) 的转移,但是多了 \(3\) 的状态,由于经过了变换,只需要加入 \((3,3)\rightarrow 3\) 的转移。这部分转移的复杂度是 \(O(6^k)\) 的。对于转移之后 \(3\) 的位置,他们是从 \((0/1,0/1)\) 转移过来的,所以真实值可能是 \(0/1/3\),所以要进行一次类似 OR 卷积的 IFWT 让他变成真实值为 \(3\) 的值。FWT 和 IFWT 的复杂度是 \(O(k4^k)\),所以总的复杂度就是 \(O(n(6^k+k4^k))\),可以通过。

#include<bits/stdc++.h>
using namespace std;
struct edge{int v,nxt;}e[205];
int n,m,u,v,cnt,h[105],w[105][256],p[105][8],dp[105][1<<16],num,tmp[1<<16];
void add(int u,int v){e[++cnt]={v,h[u]};h[u]=cnt;}
const int mod=998244353;
void Add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
struct node{int x,y,z;}go[2000005];
void init(int k,int x,int y,int z)
{
	if(k==m){go[++num]={x,y,z};return;}
	init(k+1,x,y,z);
	init(k+1,x,y|(1<<(k<<1)),z|(1<<(k<<1)));
	init(k+1,x|(1<<(k<<1)),y,z|(1<<(k<<1)));
	init(k+1,x|(2<<(k<<1)),y,z|(2<<(k<<1)));
	init(k+1,x,y|(2<<(k<<1)),z|(2<<(k<<1)));
	init(k+1,x|(3<<(k<<1)),y|(3<<(k<<1)),z|(3<<(k<<1)));
}
void fwt(int *a)
{
	for(int i=0;i<m;i++)
	{
		for(int s=0;s<(1<<(m<<1));s++)
		{
			int c=(s>>(i<<1))&3;
			if(c==0)Add(a[s+(3<<(i<<1))],a[s]);
			else if(c==1)Add(a[s+(2<<(i<<1))],a[s]); 
		}
	}
}
void ifwt(int *a)
{
	for(int i=0;i<m;i++)
	{
		for(int s=0;s<(1<<(m<<1));s++)
		{
			int c=(s>>(i<<1))&3;
			if(c==3)Add(a[s],mod-a[s-(3<<(i<<1))]),Add(a[s],mod-a[s-(2<<(i<<1))]);
		}
	}
}
void dfs(int u,int fa)
{
	dp[u][0]=1;
	for(int i=h[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);
		for(int s=0;s<(1<<(m<<1));s++)tmp[s]=dp[u][s],dp[u][s]=0;
		fwt(tmp);fwt(dp[v]);
		for(int s=1;s<=num;s++)Add(dp[u][go[s].z],1ll*tmp[go[s].x]*dp[v][go[s].y]%mod);
		ifwt(dp[u]);
	}
	for(int i=0;i<m;i++)
	{
		for(int s=0;s<(1<<(m<<1));s++)tmp[s]=dp[u][s],dp[u][s]=0;
		for(int s=0;s<(1<<(m<<1));s++)
		{
			int c=(s>>(i<<1))&3;
			if(c==0)
			{
				Add(dp[u][s],1ll*tmp[s]*(mod+1-p[u][i])%mod);
				Add(dp[u][s|(3<<(i<<1))],1ll*tmp[s]*p[u][i]%mod);
			}
			else if(c==1)
			{
				Add(dp[u][s],1ll*tmp[s]*(mod+1-p[u][i])%mod);
				Add(dp[u][s|(2<<(i<<1))],1ll*tmp[s]*p[u][i]%mod);
			}
			else if(c==2)
			{
				Add(dp[u][s],1ll*tmp[s]*(mod+1-p[u][i])%mod);
			}
			else 
			{
				Add(dp[u][s],tmp[s]);
			}
		}
	}
	for(int s=0;s<(1<<(m<<1));s++)
	{
		int ns=0;
		for(int i=0;i<m;i++)if((s>>(i<<1))&1)ns|=(1<<i);
		dp[u][s]=1ll*dp[u][s]*w[u][ns]%mod;
	}
	for(int i=0;i<m;i++)
	{
		for(int s=0;s<(1<<(m<<1));s++)tmp[s]=dp[u][s],dp[u][s]=0;
		for(int s=0;s<(1<<(m<<1));s++)
		{
			if(((s>>(i<<1))&3)==3)
			{
				Add(dp[u][s-(1<<(i<<1))],tmp[s]);
				Add(dp[u][s-(2<<(i<<1))],tmp[s]); 
			}
			else Add(dp[u][s],tmp[s]);
		}
	}
}
int main()
{
	//freopen("e.in","r",stdin);
	cin.tie(0)->sync_with_stdio(0);
	cin>>n>>m;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
		add(u,v);add(v,u);
	}
	for(int i=0;i<m;i++)for(int j=1;j<=n;j++)cin>>p[j][i];
	for(int i=1;i<=n;i++)
	{
		for(int s=0;s<(1<<m);s++)cin>>w[i][s];
	}
	init(0,0,0,0);dfs(1,0);
	int ans=0;
	for(int s=0;s<(1<<(m<<1));s++)
	{
		int flag=1;
		for(int i=0;i<m;i++)flag&=(((s>>(i<<1))&3)!=1);
		if(flag)Add(ans,dp[1][s]);
	}
	cout<<ans;
	return 0;
}

标签:P10717,状态,int,题解,复杂度,k4,转移,rightarrow
From: https://www.cnblogs.com/Harry27182/p/18322732

相关文章

  • 题解:Codeforces Round 961 (Div. 2) A
    A.Diagonals*timelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputVitaly503isgivenacheckeredboardwithasideof\(n\)and\(k\)chips.Herealizedthatallthese\(k\)chipsneedto......
  • [题解]CF958C3 Encryption (hard)
    思路先考虑\(\Theta(n^2k)\)的暴力DP。定义\(dp_{i,j}\)表示在前\(i\)个数中选取\(j\)个的最小和,转移显然:\[dp_{i,j}=\min_{1\leqk<i}\{dp_{k,j-1}+s_{k+1,i}\bmodp\}\]注意到一个性质:\(dp_{i,j}\equivs_i\pmodp\)。因为前者是前\(i\)项分为若干......
  • Java二叉树经典进阶OJ题解
     目录一、判断一颗二叉树是否为对称二叉树1.题目描述:2.代码示例:3.通过演示与分析:二、根据先序遍历结果构造二叉树1.题目描述:2.代码示例:3.通过演示与分析:三、层序遍历的非递归实现1.题目描述:2.代码示例:3.通过演示与分析:四、判断是否为完全二叉树1.题目描述:2.......
  • dify-on-wechat 数据乱串问题解决记录
    在检查dify-on-wechat应用中的数据乱串问题时,我们发现了一个关键因素:当前端和后端使用的大语言模型不一致时,会导致数据串扰问题。在深入调查和测试后,我们采取了将前后端的大语言模型改为一致的策略。在实施这一改变后,数据乱串的问题得到了有效解决。以下是详细的记录:问题现象:在dif......
  • 密码学-RSA基础题解题脚本-Python
    importgmpy2#计算大整数模块importlibnumimportrsafromCrypto.PublicKeyimportRSA#安装时安装pycryptodome模块#已知:p,q,e,cdefknown_p_q_e_c():p=int(input('请输入一个素数p:'))q=int(input('请输入另一个素数q:'))e=int(input('请输入公钥e:'))......
  • [题解]P9755 [CSP-S 2023] 种树
    P9755[CSP-S2023]种树迟来的补题本题是让最小化所有树长到指定高度日期的最大值,于是想到二分答案。那么,对于一个给定的期限\(x\),如何判断是否能在这个日期内完成任务呢?首先我们发现前\(n\)天每天都要种树,那么假设我们已经知道了每个地块最晚哪个日期种树,能保证在期限\(x\)......
  • codeforces div_2 961 题解报告
    codeforcesdiv_2961题解报告比赛链接:https://codeforces.com/contest/1995A.Diagonals题目翻译给定一个边长为\(n\)的正方形,给定\(k\),要往正方形选\(k\)个点,\(x+y\)相同的点构成对角线,问至少要几条对角线才能装下\(k\)个点。时限1s,空间限制256MB\(1\len\le100,0\l......
  • 题解:牛客多校第三场 A
    ABridgingtheGap2时间限制:C/C++1秒,其他语言2秒空间限制:C/C++1048576K,其他语言2097152KSpecialJudge,64bitIOFormat:%lld题目描述Agroupof\(n\)walkersarrivesatariverbankatnight.Theywanttocrosstheriverusingaboat,whichisinitiallyont......
  • [题解]P3187 [HNOI2007] 最小矩形覆盖
    P3187[HNOI2007]最小矩形覆盖调了半天居然是因为没判断浮点精度误差才\(\colorbox{IndianRed}{\texttt{\color{White}{WA}}}\)了\(3\)个点,其他都没有问题!警钟长鸣……首先有一个结论:凸多边形的最小外接矩形一定和它的一条边重合。这个结论,网上几乎找不到完整的证明,目前发现......
  • [POI2012] PRE-Prefixuffix 题解
    前言题目链接:洛谷。题意简述给出长为\(n\)的串\(\texttt{S}\)。求最大的\(l\)满足:\[2l\leqn\land\texttt{S}[1\ldotsl]\doteq\texttt{S}[n-l+1\ldotsn]\]其中\(\doteq\)表示循环相同。题目分析看到循环相同,套路化想到,两个字符串一定可以表示成\(\tex......