ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 P6622 [省选联考 2020 A/B 卷] 信号传递

2021-05-11 13:35:31  阅读:209  来源: 互联网

标签:cnt val 省选 题解 id int 节点 联考 las


洛谷 P6622 [省选联考 2020 A/B 卷] 信号传递

某次模拟赛的T2,考场上懒得想正解 (其实是不会QAQ),打了个暴力就骗了\(30pts\) 就火速溜了,参考了一下某位强者的题解 大概懂了一点思路,有亿点毒瘤。。。

数据范围是\(m<=23\) 的 明显是个状压么!!!

令\(f[i]\)表示,当已经确定的信号站集合为\(i\)时,此时已确定花费的最小值是多少。

此时考虑两个转移:

  1. 将左向右方向中继变换为先由初始节点中继到\(0\)号节点,再由\(0\)号节点中继到目标节点

  2. 将从右向左的中继变换为初始节点以\(−1\)的花费中继到\(0\)号节点,再由\(0\)号节点中继到目标节点

先初始化拿\(cnt[i][j]\)存一下从\(i\)到\(j\)的总数,也就是下面这个式子:

$cnt_{i,j}= \sum_{k=1}^{n-1} [S_k=i][S_{k+1}=j] $

for(int i=1,x;i<=n;i++)
{
	scanf("%d",&x);
	x--;
	if(i>1)
		cnt[las][x]++;
	las=x;
}

然后对于题面推算一下每个位置对于最终答案的加值
懒得打了。。。粘一下别人的\(LateX\)截图吧

然后,用\(val[i][j]\)简化一下上面的式子

\(vaj_{i,j}=\sum_{k\notin,k!=i}(K*cnt_{id_k,id_i}-cnt_{id_i,id_k})+\sum_{k\in j}(K*cnt_{id_i,id_k}+cnt_{id_k,id_i})\)

在处理\(val\)数组时可以发现对于\(1\)~\(i-1\)状态的是没有必要变动的,因此只需要将i之后的更改可以了

(j&((1<<i)-1)

表示前\(1\)~\(i-1\)状态不变

((j^(j&((1<<i)-1)))>>1)

对于\(i+1\)~\(n\)状态更新,向右移一位

更改时要从j状态除去一个\(lowbit\)转移过来原因见上,
剩下的就是关于上面公式的使用了

for(int i=0;i<m;i++)
{
	for(int j=0;j<m;j++)//对于0状态进行初始化
		if(j!=i)
			val[i][0]+=K*cnt[j][i]-cnt[i][j];
	for(int j=1;j<(1<<m);j++)//更新后面状态
		if(!(j&(1<<i)))
		{
			int x=j^lowbit(j),y=__builtin_ffs(j)-1;//求最后一位1
			val[i][(j&((1<<i)-1))+((j^(j&((1<<i)-1)))>>1)]=val[i][(x&((1<<i)-1))+((x^(x&((1<<i)-1)))>>1)]+K*cnt[i][y]+cnt[y][i]+cnt[i][y]-K*cnt[y][i];
		}
}

最后就是对于\(dp\)方程的转移了,再此不做过多赘述

for(int i=1;i<(1<<m);i++)
{
	f[i]=INT_MAX;//初始化赋最大值
	int sum=__builtin_popcount(i);//求i状态中1的数量
	for(int j=0;j<m;j++)
		if(i&(1<<j))
		{
			int x=i^(1<<j);
			f[i]=min(f[i],f[x]+sum*val[j][(x&(1<<j)-1)+((x^x&(1<<j)-1)>>1)]);
		}
}

\(code\)

#include<bits/stdc++.h>
using namespace std;
const int M=23;
int n,m,K,las,cnt[M+5][M+5],val[M+5][1<<(M-1)],f[1<<M];
int lowbit(int x)
{
	return x&(-x);
}
int main()
{
	scanf("%d%d%d",&n,&m,&K);
	for(int i=1,x;i<=n;i++)
	{
		scanf("%d",&x);
		x--;
		if(i>1)
			cnt[las][x]++;
		las=x;
	}
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<m;j++)
			if(j!=i)
				val[i][0]+=K*cnt[j][i]-cnt[i][j];
		for(int j=1;j<(1<<m);j++)
			if(!(j&(1<<i)))
			{
				int x=j^lowbit(j),y=__builtin_ffs(j)-1;
				val[i][(j&((1<<i)-1))+((j^(j&((1<<i)-1)))>>1)]=val[i][(x&((1<<i)-1))+((x^(x&((1<<i)-1)))>>1)]+K*cnt[i][y]+cnt[y][i]+cnt[i][y]-K*cnt[y][i];
			}
	}
	for(int i=1;i<(1<<m);i++)
	{
		f[i]=INT_MAX;
		int sum=__builtin_popcount(i);
		for(int j=0;j<m;j++)
			if(i&(1<<j))
			{
				int x=i^(1<<j);
				f[i]=min(f[i],f[x]+sum*val[j][(x&(1<<j)-1)+((x^x&(1<<j)-1)>>1)]);
			}
	}
	printf("%d",f[(1<<m)-1]);
	return 0;
}

完结撒花\(QAQ\)

标签:cnt,val,省选,题解,id,int,节点,联考,las
来源: https://www.cnblogs.com/Varuxn/p/14754851.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有