【XSY3988】安静(数学,根号分类讨论)

题面

安静

题解

首先题目的条件可以看作是:如果当前时刻 \(X\)\(T_i\)\(j\),那么就会得到 \(f_i(j)\) 的贡献。构造一个答案时刻 \(X\),使得总贡献最大,求总贡献的最大值。

注意到 \(t\leq 120\),那么我们将 \(T_i\) 相同的归到一类:设 \(f(t,j)\) 表示当前时刻 \(X\)\(t\)\(j\) 时的总贡献,那么接下来整道题都与 \(n\) 无关了。

现在题目的要求变成了:如果当前时刻 \(X\)\(t\)\(j\),那么就会得到 \(f(t,j)\) 的贡献。构造一个答案时刻 \(X\),使得总贡献最大,求总贡献的最大值。


先来考虑一种最朴素的做法。

令集合 \(\mathbb{P}=\{2,3,5,7,\cdots,113\}\) 表示所有小于等于 \(120\) 的质数的集合,那么所有的 \(t\) 所包含的所有质因子都在集合 \(\mathbb{P}\) 内。

\(p\) 为集合 \(\mathbb{P}\) 内某一元素,定义 \(m_p=\left\lfloor\log _p 120\right\rfloor\),那么 \(m_p\) 就表示在所有的 \(t\) 的分解质因数中 \(p\) 的幂次最高能到多少。

对于任意一个 \(1\leq t\leq 120\),考虑 \(X\)\(t\) 的余数是什么。

考虑一个数 \(M=\prod\limits_{p \in \mathbb{P}}p^{m_p}\),发现 \(M\) 始终是 \(t\) 的倍数,所以 \(X\equiv X-M\pmod t\),即 \(X\equiv X\bmod M\pmod t\)

那么我们可以枚举 \(X\)\(M\) 的余数 \(r\),那么 \(X\equiv r\pmod t\),那么我们就可以算此时的贡献了。

那么我们就能在把无限次数地枚举 \(X\) 找最大贡献转换成有限次数地枚举 \(r\) 找最大贡献了。

\(T=120\),那么此算法的时间复杂度为 \(O(MT)\),考虑继续优化。

下面用 \([a,b]\) 表示 \(a,b\) 的最小公倍数。

我们考虑将 \(f(2^{m_2},*)\) 合并到 \(f(2^{m_2-1},*)\),即 \(f(64,*)\) 合并到 \(f(32,*)\)

首先,如果 \(X\bmod 32=r\),那么肯定有 \(X \bmod 64=r\)\(X\bmod 64=32+r\)

假设当前 \(X\bmod 32=r\)\(X\bmod 64=r\),但如果 \(X\bmod 64=32+r\) 的贡献会更大。

我们考虑一个数 \(M'=32\times \prod\limits_{p\in \mathbb{P},p\neq 2}p^{m_p}\),显然对于所有的 \(1\leq t\leq 120\),都有 \(M'\equiv 0\pmod{t}\),除了 \(t=64\)\(M'\equiv 32\pmod{64}\)

那么我们此时让 \(X\gets X+M'\),就能使得 \(X\) 模其他数的值不变,而 \(X\)\(64\) 变成 \(32+r\) 了。

所以可以把 \(\max\big(f(64,r),f(64,32+r)\big)\) 的贡献合并到 \(f(32,r)\) 上。

同理可以把 \(f(81,*)\) 合并到 \(f(27,*)\) 上。

我们又考虑把 \(f(1\times 7^2,*),f(2\times 7^2,*)\) 合并到 \(f([1,2]\times 7,*)\) 上。

同理可以把 \(f(1\times 5^2,*),f(2\times 5^2,*),f(3\times 5^2,*),f(4\times 5^2,*)\) 合并到 \(f([1,2,3,4]\times 5,*)\) 上,

那么 \(2,3,5,7\) 的最高次分别降为 \(2^5,3^3,5,7\)

(当然也可以把 \(2^5\)\(3^3\)\(5\)\(7\) 的方法降下来,不过要保证最小公倍数乘上 \(p^k\) 要能被 \(M'\) 整除)

我们把 \(\mathbb{P}\) 分为两类 \(\mathbb{P}_1\)\(\mathbb{P}_2\),其中 \(\mathbb{P}_1=\{2,3,5,7\}\) 表示所有小于等于 \(\sqrt{120}\) 的质数的集合, \(\mathbb{P}_2=\{11,13,\cdots,113\}\) 表示所有大于 \(\sqrt{120}\) 小于等于 \(120\) 的质数的集合。

设集合 \(\mathbb{T}_1\) 表示所有的整数 \(t\) 满足 \(1\leq t\leq 120\)\(t\) 不含大于 \(\sqrt{120}\) 的质因子,集合 \(\mathbb{T}_2\) 表示所有的整数 \(t\) 满足 \(1\leq t\leq 120\)\(t\) 包含大于 \(\sqrt{120}\) 的质因子。显然 \(\mathbb{T_1}\) 中的数的所有质因子只存在于 \(\mathbb{P}_1\) 内,而 \(\mathbb{T_2}\) 中的数的质因子可以同时存在 \(\mathbb{P}_1,\mathbb{P}_2\) 内,也可以只存在于 \(\mathbb{P}_2\) 内,但存在于 \(\mathbb{P}_2\) 内的质因子只能有一个,且其幂次一定为 \(1\)

我们考虑分开讨论:先枚举 \(X\)\(2^5\times 3^3\times 5\times 7=30240\) 的余数 \(r\),计算集合 \(\mathbb{T}_1\) 的答案,再和集合 \(\mathbb{T}_2\) 合并。

代码如下:

#include<bits/stdc++.h>

#define T 125

using namespace std;

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;
}

const int P=30240;
const int p2[]={26,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113};

int n,ans,f[T][T],s[T];
bool vis[T];

void clear(int x)
{
	memset(f[x],0,sizeof(f[x]));
}

int main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		int t=read();
		for(int j=0;j<t;j++)
			f[t][j]+=read();
	}
	for(int i=0;i<32;i++)
		f[32][i]+=max(f[64][i],f[64][i+32]);
	clear(64);
	for(int i=0;i<27;i++)
		f[27][i]+=max(f[81][i],max(f[81][i+27],f[81][i+54]));
	clear(81);
	for(int i=0;i<14;i++)
	{
		int maxn=0;
		for(int j=i;j<112;j+=14)
			maxn=max(maxn,f[49][j%49]+f[98][j]);
		f[14][i]+=maxn;
	}
	clear(49),clear(98);
	for(int i=0;i<60;i++)
	{
		int maxn=0;
		for(int j=i;j<360;j+=60)
			maxn=max(maxn,f[25][j%25]+f[50][j%50]+f[75][j%75]+f[100][j%100]);
		f[60][i]+=maxn;
	}
	clear(25),clear(50),clear(75),clear(100);
	for(int i=1;i<=p2[0];i++)
		for(int j=p2[i];j<=120;j+=p2[i]) vis[j]=1;
	for(int r=0;r<P;r++)
	{
		int sum=0;
		for(int i=1;i<=120;i++)
			if(!vis[i]) sum+=f[i][r%i];
		for(int i=1;i<=p2[0];i++)
		{
			memset(s,0,sizeof(s));
			int p=p2[i];
			for(int j=p;j<=120;j+=p)
			{
				int now=r%j;
				do
				{
					s[now%p]+=f[j][now];
					now=(now+P)%j;
				}while(now!=r%j);
			}
			int maxn=0;
			for(int j=0;j<p;j++)
				maxn=max(maxn,s[j]);
			sum+=maxn;
		}
		ans=max(ans,sum);
	}
	printf("%d\n",ans);
	return 0;
}
/*
3
2 0 1
3 1 2 0
4 1 0 2 0
*/
/*
3
6 1 3 5 2 7 4
10 3 7 2 2 5 1 8 9 4 6
15 4 5 8 7 8 8 5 4 5 2 7 5 5 4 7
*/

这篇题解很多地方讲得不是很清楚,需要自己手推。

posted @ 2022-10-31 07:23  ez_lcw  阅读(48)  评论(0编辑  收藏  举报