2021牛客暑期多校训练营5 G.Greater Integer, Better LCM(搜索,子集合并)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营5 G.Greater Integer, Better LCM(搜索,子集合并)相关的知识,希望对你有一定的参考价值。

LINK

l c m ( a + x , b + y ) lcm(a+x,b+y) lcm(a+x,b+y)的意义就是对于每个质因子幂取 a + x a+x a+x b + y b+y b+y中更大的那个

而且 a + x a+x a+x b + y b+y b+y在每个质因子上,至少一个是最高次幂,这才能满足 l c m ( a + x , b + y ) = c lcm(a+x,b+y)=c lcm(a+x,b+y)=c

考虑枚举 a + x a+x a+x b + y b+y b+y在每个质因子取到的幂次,复杂度是不超过 O ( 2 ∑ q i ) O(2^{\\sum\\limits q_i}) O(2qi)

这些状态我们可以爆搜出来,同时用一个二进制数表示这些状态在哪些质因子取到最高次幂

于是定义 f [ i ] f[i] f[i]表示当质因子限制状态为 i i i时的大于 a a a的最小值

定义 g [ i ] g[i] g[i]表示质因子限制状态为 i i i时大于 b b b的最小值

于是可以暴力枚举 f [ i ] f[i] f[i] g [ j ] g[j] g[j]若满足 i ∣ j = 2 ∑ q i − 1 i|j=2^{\\sum q_i}-1 ij=2qi1可以更新答案

这样的复杂度是 2 ∑ q i ∗ 2 ∑ q i 2^{\\sum q_i}*2^{\\sum q_i} 2qi2qi

如果枚举 f [ i ] f[i] f[i]后继续枚举 i ⊕ ( 2 ∑ q i − 1 ) i\\oplus (2^{\\sum q_i}-1) i(2qi1)的子集可以做到 3 n 3^{n} 3n的复杂度

还是不太能过的样子,考虑让 f [ i ] f[i] f[i]表示所有包含子集 i i i的状态中的最小值, g g g同理

利用子集 d p dp dp的思想,每次只更新子集的极大真子集,更小的子集会被极大真子集更新

总体复杂度 O ( n ∗ 2 n ) O(n*2^n) O(n2n)

#include<bits/stdc++.h>
using namespace std;
using i128 = __int128;
const int maxn = (1<<20);
const i128 inf = 1e36;
i128 in() 
{
	static char buf[110]; i128 x = 0; scanf("%s", buf);
	for (char *p = buf; *p; ++p) x = x * 10 + (*p - '0');
	return x;
}
void out( i128 x ) 
{
	if (x >= 10) out(x / 10);
	putchar('0' + x % 10);
}
inline i128 min(i128 x,i128 y){ return x<y?x:y; }
int n,mx,p[maxn],q[maxn];
i128 a,b,f[maxn],g[maxn];
void dfs(int id,i128 x,int val)
{
	if( x>=a )	f[val] = min( f[val],x );
	if( x>=b )	g[val] = min( g[val],x );
	if( id>n )	return;
	for(int i=0;i<=q[id];i++)
	{
		dfs( id+1,x,val | ( (i==q[id])*(1<<(id-1)) )  );
		x *= p[id];
	}
}
void zjdp()
{
	for(int i=mx;i>=0;i--)
	for(int j=0;j<n;j++)
	{
		if( ((i>>j)&1)==0 )	continue;
		f[i^(1<<j)] = min( f[i^(1<<j)],f[i] );
		g[i^(1<<j)] = min( g[i^(1<<j)],g[i] );
	}
}
int main()
{
	cin >> n; mx = (1<<n)-1;
	for(int i=0;i<=mx;i++)	f[i] = g[i] = inf;
	for(int i=1;i<=n;i++)	cin >> p[i] >> q[i];
	a = in(); b = in();
	dfs( 1,1,0 ); zjdp();
	i128 ans = inf;
	for(int i=mx;i>=0;i--)
		ans = min( ans,f[i]+g[mx^i]-a-b );
	out( ans );
}

以上是关于2021牛客暑期多校训练营5 G.Greater Integer, Better LCM(搜索,子集合并)的主要内容,如果未能解决你的问题,请参考以下文章

2021牛客暑期多校训练营5,签到题BDHJK

2021牛客暑期多校训练营2

2021牛客暑期多校训练营4

2021牛客暑期多校训练营9

2021牛客暑期多校训练营3

2021牛客暑期多校训练营8,签到题ADEK