CF1646E Power Board

CF1646E Power Board

给一个复杂度与 \(m\) 无关的做法。

考虑什么时候数字出现重复。

观察每一行。

发现当存在 \(i,j\) 满足 \(i,j\le n\)\(j=i^k\) 的时候第 \(i\) 行和第 \(j\) 行会出现重复的。

那么我们分段处理。

我们找到最小的 \(i\) 满足不存在 \(j\) 使得 \(j^k=i\)

那么我们将 \(i,i^2,\dots ,i^k\) 这几行的数放在一起处理。

注意到与这几行的包括数是 \(i,i^2,\dots,i^m \cup i^2,i^4,\dots,i^{2m}\cup i^3,i^6,\dots i^{3m}\cup\dots\)

发现这些数中如果指数不一样那么数就不一样。所以我们只要把指数拿下来去重就行。

问题就变成:

\(1,2,\dots ,m \cup2,4,\dots,2m\cup3,6,\dots,3m\cup\dots\)

这些数中有多少个不重复的数。

发现是所有 \([1,k\times m]\)\(k\) 的倍数的并集。

我们可以大力容斥去做。

复杂度与 \(m\) 无关,但是具体是多少我并不会证,输出了下次数大概是 \(n\log n\) 级别的。(\(10^6\) 跑了 \(2\times10^7\) 次)。

所以这题的 \(m\) 可以被强化到 \(1e18\) 哩!

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 1e6+5;
int n,m,lg[MAXN];
bool vis[MAXN];
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
ll lcm(ll x,ll y){return x/gcd(x,y)*y;}
int main()
{
	for(int i=2;i<=1000000;++i) lg[i]=lg[i>>1]+1;
	scanf("%d %d",&n,&m);
	ll Ans=1;
	for(ll i=2;i<=n;++i)
	{
		if(vis[i]) continue;
		int siz=1;
		for(ll j=i*i;j<=n;j=j*i) vis[j]=1,++siz;
		for(int s=1;s<(1<<siz);++s)
		{
			int c=__builtin_popcount(s);
			ll g=lg[(s&(-s))]+1,v=1;
			for(int j=0;j<siz;++j) if((1<<j)&s) v=lcm(v,j+1);
			if(c&1) Ans+=g*m/v;
			else Ans-=g*m/v;
            //注意这里容斥的时候交集一定是在 1到最小的km 之间 
		}
	}
	printf("%lld\n",Ans);
	return 0;
}
posted @ 2022-04-14 22:21  夜空之星  阅读(34)  评论(0编辑  收藏  举报