首页 > 其他分享 >CodeForces1741G-Kirill and Company题解

CodeForces1741G-Kirill and Company题解

时间:2023-08-24 17:22:13浏览次数:49  
标签:int 题解 捎带 Kirill CodeForces1741G tot 集合 cdot dp

\(\large\text{CodeForces1741G-Kirill and Company题解}\)

题面传送门(有翻译(由黄巨佬提供))

思路

预处理

因为 \(k\) 很小,所以可以先 bfs 预处理出家在 \(i(2\le i\le n)\) 的人能捎带上哪些集合的人,在表示集合时用一个 \(0\) 到 \(2^k-1\) 的整数 \(j\) 表示,若 \(j\) 在二进质下的从小到大第 \(l\) 位是 \(1\),那么这个集合就包含第 \(l\) 的没车的人。

在 bfs 从 \(i\) 转移到 \(j\) 时,如果 \(i\) 能成为 \(1\) 到 \(j\) 的最短路上的点,那么家在 \(i\) 的人能捎带上的人的集合家在 \(j\) 的人也能捎带上,注意集合里还要加上家在 \(j\) 点且没车的人。

预处理完后做 dp :
  • 设 \(dp_{i,j}\) 表示前 \(i\) 个人是否能捎带上 \(j\) 集合里的所有人。
  • 转移(扩散型):
    • 如果第 \(i+1\) 个人没车,那么如果 \(dp_{i,j}=1\) 则 \(dp_{i+1,j}=1\) 否则 \(dp_{i+1,j}=0\) 。
    • 如果第 \(i+1\) 个人有车,那么如果 \(dp_{i,j}=1\) 且第 \(i+1\) 个人回家的路上能捎带上集合 \(l\) 的人,则对于 \(j\) 和 \(l\) 的并集 \(q\),\(dp_{i+1,q}=1\)。
  • 在表示集合的时候,可以用预处理时的方法,那么 \(j\) 和 \(l\) 的并集就是 \(j|l\)。
答案

对于每个 \(dp_{tot,j}=1\) 的 \(j\),输出集合大小最大的 \(j\) 的集合大小。

时间复杂度

对于每个测试点

bfs

\(O(m\cdot 2^k)\)

dp

\(O(tot\cdot 2^{2k})\)

\(O(m\cdot 2^k+tot\cdot 2^{2k})\)

空间复杂度

\(O(n\cdot 2^k+tot\cdot 2^k)\)

代码(不建议在做出来之前看)

优美的码风

#include <bits/stdc++.h>

using namespace std;

const int kMaxN=1e4+1,kMaxS=1<<6;

int t,n,m,p[kMaxN],o,h[kMaxN],k,c[kMaxN],dp[kMaxN][kMaxS],ma;
bool a[kMaxN][kMaxS],f[kMaxN];
vector<int>b[kMaxN];
queue<int>q;

void R(int x,int l,int j){
	if(j<=c[x]){
		if(j<c[x]){
			c[x]=j;
			q.push(x);
		}
		for(int i=0;i<(1<<k);i++){
			a[x][(i|p[x])]|=a[l][i];
		}
	}
}

int S(int x){
	int ans=0;
	for(;x;ans++,x-=(x&(-x))){
	}
	return ans;
}

int main() {
	ios::sync_with_stdio(0),cin.tie(0);
	for(cin>>t;t--;){
		cin>>n>>m;
		for(int i=1,u,v;i<=m;i++){
			cin>>u>>v;
			b[u].push_back(v),b[v].push_back(u);
		}
		cin>>o;
		for(int i=1;i<=o;i++){
			cin>>h[i];
		}
		cin>>k;
		fill(p+1,p+n+1,0);
		fill(f+1,f+o+1,0);
		for(int i=1,a;i<=k;i++){
			cin>>a;
			f[a]=1;
			p[h[a]]+=(1<<(i-1));
		}
		fill(a[1],a[n]+kMaxS,0);
		a[1][0]=1;
		fill(c+1,c+n+1,n+1);
		for(R(1,0,0);q.size();q.pop()){
			for(int i:b[q.front()]){
				R(i,q.front(),c[q.front()]+1);
			}
		}
		fill(dp[0],dp[o]+kMaxS,0);
		dp[0][0]=1;
		for(int i=0;i<o;i++){
			for(int j=0;j<(1<<k);j++){
				if(dp[i][j]){
					if(!f[i+1]){
						for(int l=0;l<(1<<k);l++){
							if(a[h[i+1]][l]){
								dp[i+1][j|l]=1;
							}
						}
					}else{
						dp[i+1][j]=1;
					}
				}
			}
		}
		ma=0;
		for(int i=0;i<(1<<k);i++){
			ma=max(ma,S(i)*dp[o][i]);
		}
		cout<<k-ma<<"\n";
		for(int i=1;i<=n;i++){
			b[i].clear();
		}
	}
	return 0;
}

标签:int,题解,捎带,Kirill,CodeForces1741G,tot,集合,cdot,dp
From: https://www.cnblogs.com/cyxarr/p/17652001.html

相关文章

  • Codeforces Round #849 (Div. 4) 题解
    第一次打$\text{Div.4}$,感觉体验还行,差一题AK。##A直接使用if语句判断某个字符是否在字符串$\text{codeforces}$中出现过,幼儿园小朋友都会做。时间复杂度$\mathcal{O}(T)$,空间复杂度$\text{O}(1)$。ACCode##B用两个变量$x,y$记录当前走到哪里。若出现过$x=1,y=1$的......
  • CF36D New Game with a Chess Piece 题解
    前言:都大半年没在洛谷上提交过题解了。SPOJ上有双倍经验,题号为SP7602。我看题解区的大佬们有的正经用博弈论做,有的打表,但是感觉没有讲得很形象,这篇题解将生动讲述打表做法,同时为了让大家在感性理解后,还可以理性理解,会附上证明(这部分参考了别的题解)。正文:Step1:打表找规律......
  • CF54C First Digit Law 题解
    题目传送门\(Solution\):一个比较简单的数位dp处理技巧加上一个暴力的dp。设\(p_i\)为区间\([l_i,r_i]\)中出现\(1\)开头的数的概率。考虑\(solve(x)\)函数为求出\([1,x]\)中开头为\(1\)的个数。显然低于\(x\)的位数的数是全部能取到的,这时候开头为\(1\)......
  • 题解 数数
    题目链接可持久化平衡树看上去很行的样子,但是我不会啊。。。先来考虑一个简化版的问题:求区间\([1,n]\)中\(\leH_i\)的元素个数。这显然是好做的,用权值树状数组就行。回到本题,显然:询问区间\([l,r]\)中\(\leH_i\)的个数,等价与区间\([1,r]\)的答案减去区间\([1,l-1]......
  • 国标视频云服务EasyGBS国标视频平台迁移服务器后无法启动的问题解决方法
    国标视频云服务EasyGBS支持设备/平台通过国标GB28181协议注册接入,并能实现视频的实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。平台部署简单、可拓展性强,支持将接入的视频流进行全终端、全平台分发,分发的视频流包括RTSP、RTMP、FLV、HLS、WebRTC等格......
  • P3742题解
    思路只需要让z串做到和y串一样,就得让y串每个字母(题意如此)均小于x串。所以只要x串有一项小于y串,那么就输出-1,否则输出y串。下面是核心代码:#include<bits/stdc++.h>usingnamespacestd;intn;stringx,y;intmain(){ cin>>n>>x>>y; for(inti=0;i<n;i++) { if(x[i]......
  • 【问题解决】容器部署MySQL的数据在docker commit导出的镜像中丢失
    问题起因最近公司有个甲方项目参加竞赛,要求在(基于kubeflow/arena)平台上部置应用,可以将MySQL打包在应用一起,也可以分开部署,没有提供volume相关的支持。大意是可以把初始好的数据直接拿到平台上。经过本人在Linux虚机中启动MySQL容器导入数据再dockercommit出镜像部署到平台......
  • 「题解」Codeforces 825G Tree Queries
    点权转边权,把边权设为两个端点的\(\min\),然后发现询问\(x\)的答案,就是询问\(x\)与所有黑点的虚树,边权的\(\min\)是多少。假设要判定答案是否\(\geqk\),那么就是询问\(x\)只经过\(\geqk\)是否能到达所有黑点,于是想到建立Kruskal重构树,那么\(x\)与所有黑点的LCA......
  • 题解 P8816 [CSP-J 2022] 上升点列
    P8816[CSP-J2022]上升点列题目大意给定\(n\)个点,你可以任意添加\(k\)个点,从中选择若干点使得序列中任意相邻两点间的欧几里得距离恰好为\(1\)而且横坐标、纵坐标值均单调不减。换言之,求二维最长上升子序列。solution:很容易想到动态规划,根据最长上升子序列的套路,可以......
  • P1830题解
    思路:利用桶存储轰炸区域,双重循环。在存储轰炸区域时将次数刷新,也就是pos[j][k]=i;。下面是核心代码:for(inti=1;i<=x;i++){ intx1,x2,y1,y2; cin>>x1>>y1>>x2>>y2; for(intj=x1;j<=x2;j++) { for(intk=y1;k<=y2;k++) { vis[j][k]++; pos[j][k]=i; } }......