首页 > 其他分享 >【XSY4055】小K的疑惑(模拟最短路,值域并查集)

【XSY4055】小K的疑惑(模拟最短路,值域并查集)

时间:2022-10-31 07:35:32浏览次数:44  
标签:ch int XSY4055 短路 查集 更新 值域 now mod

题面

小K的疑惑

题解

以下的数都是在 \(b\) 进制意义下讨论。

默认 \(n\geq b\),否则 \(n< b\) 可以特判答案为 \(1\)。

考虑 DP,设 \(d_r\) 表示所有模 \(n\) 余 \(r\) 的正整数中非零位个数的最小值,那么我们要求的即为 \(d_0\)。

我们考虑从 \(d_r\) 转移出去:

  • 我们可以考虑把这个模 \(n\) 余 \(r\) 的数末尾添上一个 \(0\),此时余数变为了 \(br\bmod{n}\),非零位个数不变,故:

    \[d_{br\bmod n}\gets d_r \]

  • 我们也可以考虑把这个模 \(n\) 余 \(r\) 的数末尾添上一个非零数 \(s\)(\(1\leq s<b\)),此时余数变为了 \((br+s)\bmod{n}\),非零位个数加 \(1\),故:

    \[d_{(br+s)\bmod n}\gets d_r+1 \]

那么初始状态也就出来了:

\[d_r\gets 1\quad(1\leq r<b) \]

暴力建边是 \(O(nb)\) 的,接下来考虑如何优化转移。

我们把 \(d_r\) 看做点 \(r\),那么 \(d_r\) 的转移就是在图上跑 \(01\) 最短路。

利用到边权只能为 \(0\) 或 \(1\) 的优秀性质,我们考虑模拟最短路中的 \(\operatorname{bfs}\):大概思路是先一直贪心走 \(0\) 边并对没访问过的点进行更新,再对刚刚所有更新的点走一次 \(1\) 边并对没访问过的点进行更新,再重复上述过程。

注意到一个点的 \(0\) 边只有一条,所以走 \(0\) 边时如果走到的点已经被更新了,那么它往后走 \(0\) 边的点也肯定被更新了,就无需继续更新。所以走 \(0\) 边的部分我们直接暴力更新即可。总时间复杂度 \(O(n)\)。

而对于每一个要向外更新的点,我们需要找到它的 \(1\) 边中所有未被更新的点。注意到每个点向外连的 \(1\) 边是一段区间,所以我们用并查集维护即可。总时间复杂度 \(O(n\cdot\alpha (n))\)。

代码如下:

#include<bits/stdc++.h>

#define N 10000010
#define re register

using namespace std;

namespace modular
{
	int mod;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int n,num,b,d[N],nxt[N];
int fa[N],tor[N];
bool flag;

int find(int x)
{
	return x==fa[x]?x:(fa[x]=find(fa[x]));
}

inline void merge(int x,int y)
{
	int a=find(x),b=find(y);
	fa[b]=a,tor[a]=max(tor[a],tor[b]);
}

inline void change(int i)
{
	if(i-1>=0&&d[i-1]) merge(i-1,i);
	if(i+1<n&&d[i+1]) merge(i,i+1);
}

queue<int>q[2];

void update(int u)
{
	int now=u;
	do
	{
		d[now]=num;
		change(now);
		q[flag^1].push(now);
		now=nxt[now];
	}while(!d[now]);
}

void work(int l,int r)
{
	for(re int i=l;i<=r;i++)
	{
		if(d[i])
		{
			int rt=find(i);
			i=tor[rt];
			continue;
		}
		d[i]=num;
		update(i);
	}
}

int main()
{
	mod=n=read(),b=read();
	if(n<b)
	{
		puts("1");
		return 0;
	}
	for(re int i=0;i<n;i++) fa[i]=tor[i]=i;
	for(re int i=0;i<n;i++) nxt[i]=1ll*i*b%n;
	num=1,flag=0;
	work(1,b-1);
	while(!d[0])
	{
		num++,flag^=1;
		while(!q[flag].empty())
		{
			int u=q[flag].front();
			q[flag].pop();
			int l=add(nxt[u],1),r=add(nxt[u],b-1);
			if(l<=r) work(l,r);
			else work(l,n-1),work(0,r);
		}
	}
	printf("%d\n",d[0]);
	return 0;
}
/*
79 2
*/

标签:ch,int,XSY4055,短路,查集,更新,值域,now,mod
From: https://www.cnblogs.com/ez-lcw/p/16842962.html

相关文章

  • 普及-的并查集(都是板子)
        #include<bits/stdc++.h>usingnamespacestd;constintN=1e5+7;structNode{ intbn,ed,t;}a[N];intf[N];intfind(intx){returnx==f[x]?x:......
  • 【XSY2485】MST(最小生成树+倍增lca+并查集)
    题面Description给定一个\(n\)个点\(m\)条边的连通图,保证没有自环和重边。对于每条边求出,在其他边权值不变的情况下,它能取的最大权值,使得这条边在连通图的所有最小生成......
  • 【PR #2】史莱姆(值域分段)
    首先看单次询问我们怎么做。对于一个人,他的最优策略显然是不断吃最小的,并看最后能不能吃完。假设我们把区间内的数排好序了,设为\(a_1\leqa_2\leq\cdots\leqa_n\)。对......
  • 【bzoj4358】permu【XSY1535】seq(莫队+并查集)
    考虑莫队,但是我们发现这个东东只支持\(ins\)(至于怎么支持等会再讲),不支持\(del\)操作,所以我们构造一种只\(ins\)不\(del\)的莫队。由于我们按莫队的方法排序,第一关键字为\(......
  • 并查集--翻译机的个数(顺丰2020年笔试)
    某学术会议上,一共有n个人参加,现在已知每个人会的语言(一个人可能不会任何语言)。现在有一种学习机,每一个学习机可以在会议期间使一个人暂时掌握一种自己不会的语言,问要使得任......
  • 并查集--村村通
    题目描述某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府“村村通工程”的目标是使全市任何两个城镇间都可以实现交通(但不一定有直......
  • 并查集--同时修路得到的最短时间
    题目背景AA地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。题目描述给出A地区的村庄数NN,和公路数MM,公路是双向的。并告诉你每条公路的连......
  • ACWing - 4493 -- 思维题&&并查集&&dfs
    题目描述环形连通分量思路对于一个无向图中的简单环(环中边的数量等于点的数量),有一个很强的性质:每个点的度数等于\(2\)。那么我们只需要先找出所有的连通块,然后判......
  • MST算法-堆优化Prim与并查集优化Kruskal
    生成树首先,生成树是相对于连通图来说的。它是一个连通图的子图,而且没有环,也可以看成是一棵树。对于生成树,其所有结点的根节点都是同一个。生成树有以下两个性质:生成树......
  • POJ 2588(解析几何+并查集)
    题目就是早从左到右的路注意输入的实数这题图画好就行,别像我一开始把图弄反就成从上开始找,若找到一个与下边界相邻的就无解,找到与左边相邻的记圆与左边界相交的下边的点(相当......