1 条题解

  • 0
    @ 2025-8-24 22:15:00

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar nofind
    苟到省选退役的蒟蒻

    搬运于2025-08-24 22:15:00,当前版本为作者最后更新于2020-01-01 19:53:07,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意

    我自闭了,连蓝题都不会了,还得看题解。

    以下是我理解的官方做法,献给给广大没看懂官方题解的神仙们。作者蒟蒻,如果有什么不对的地方请指出。

    观察题目的限制,发现qq是一个pzp^z的形式,因此我们可以考虑每个质数pp

    对于每个质数pp,我们求出一个010-1stateistate_i,其中第ii位为11则表示存在一个数,它分解后pp这个质因子的次幂为ii。特殊地,如果一个数不含pp这个质因子,那么第00位为11pp的次幂的上界很小,p=2p=2时最大,才log2\log_2级别,因此是开得下的。

    现在我们考虑通过题中的操作使得a1...na_{1...n}相同的过程:
    对于每个质数pp,显然只有所有aia_i分解后的pp的次幂相同才会满足条件。

    先假设我们要将所有的aia_ipp的次幂都消成00

    此时,我们要对pp的状态求出一个最小的集合,满足将这个集合内的数任意相加可以拼出pp的状态中所有的位置。

    就拿官方题解里的例子吧:
    对于10001110101000111010,在1,3,4,5,91,3,4,5,9位上是11(注意我们是从右向左从零开始数的),于是f(1000111010)2=3f_{(1000111010)_2}=3,因为我们可以通过{1,3,5}\{1,3,5\}拼出所有的数。(1=11=13=33=34=1+34=1+35=55=59=1+3+59=1+3+5

    此时我们在q=p1q=p^1时操作分解后pp的次幂为1,4,91,4,9的位置,在q=p3q=p^3时操作分解后pp的次幂为3,4,93,4,9的位置,在q=p5q=p^5时操作分解后pp的次幂为5,95,9的位置,那么所有的数中pp的次幂都为00

    那么我们就设fsf_s表示状态ss的答案,我们可以dfsdfs求出。

    但是包含ss的状态tt(即sstt的子集)的答案ftf_t也可以更新fsf_s(能拼出tt就能拼出ss),我们再枚举每个状态,更新它的子集即可。

    现在考虑我们不把所有的aia_i中的pp的次幂消成00的情况。

    这时候需要满足该状态最低位(即第00位)不为00,因为为00的话就说明有一个数根本就没有pp这个质因子,那肯定要全消完。

    那么我们保留pkp^k就相当于sp>>ks_p>>k这个状态的答案,还是拿之前的那个举例:
    10001110101000111010,在1,3,4,5,91,3,4,5,9位上是11。 我们现在保留p1p^1,也就是我们要找最小的集合,使其能拼成0,2,3,4,80,2,3,4,8,那么对应的状态就是sp>>1s_p>>1

    由衷地感叹:这题的确是道思维好题。

    code(真·抄的官方题解):

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+10;
    const int maxm=20;
    int n,ans;
    int a[maxn],f[1<<maxm],state[1<<maxm],cnt[1<<maxm];
    bool vis[maxn];
    vector<int>prime;
    inline void pre_work()
    {
    	vis[1]=1;
    	for(int i=2;i<=1000000;i++)
    	{
    		if(!vis[i])prime.push_back(i);
    		for(unsigned int j=0;j<prime.size()&&i*prime[j]<=1000000;j++)
    		{
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0)break;
    		}
    	}
    }
    void dfs(int dep,int now,int s)
    {
    	f[s]=min(f[s],dep-1);
    	if(dep>5)return;
    	for(int i=now;i<=20;i++)dfs(dep+1,i,(s|(s<<i))&((1<<20)-1));
    }
    int main()
    {
    	pre_work();
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    	memset(f,0x3f,sizeof(f));
    	dfs(1,1,1);
    	for(int s=(1<<20)-1;s;s--)
    		for(int j=1;j<=20;j++)
    			if(!((s>>(j-1))&1))f[s]=min(f[s],f[s|(1<<(j-1))]);
    	for(int s=1;s<(1<<20);s++)if(!(s&1))f[s]=min(f[s],f[s>>1]);
    	for(int i=1;i<=n;i++)
    	{
    		int tmp=a[i];
    		for(unsigned int j=0;j<prime.size()&&prime[j]*prime[j]<=tmp;j++)
    		{
    			if(tmp%prime[j])continue;
    			int k=0;
    			while(tmp%prime[j]==0)k++,tmp/=prime[j];
    			state[prime[j]]|=1<<k;cnt[prime[j]]++;
    		}
    		if(tmp>1)cnt[tmp]++,state[tmp]|=2;
    	}
    	for(int i=2;i<=1000000;i++)
    	{
    		if(cnt[i]!=n)state[i]|=1;
    		ans+=f[state[i]];
    	}
    	printf("%d",ans);
    	return 0;
    }
    
    • 1

    信息

    ID
    4798
    时间
    1000ms
    内存
    128MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者