博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

BZOJ.3944.Sum(杜教筛)

BZOJ
洛谷

这题杜教筛已经被Min_25吊打了。


又写个模板题用了半晚上。。

卡常写法

还非常短。。

[Update] 卡了半天常,可能还不如换unordered_map快=-=
见:https://www.luogu.org/recordnew/show/18243951
也可能是我以前代码太丑了=-=

//35332 kb	7608 ms
//跟Kelin dalao学一波卡常。怎么还是很慢QAQ 
//phi[]要longlong!
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=2e6;

int cnt,Max,P[N>>3];
LL phi[N],mu[N],sum[20005][2];
bool Not_p[N],vis[20005];

void Make_Table()
{
	mu[1]=phi[1]=1;
	for(int i=2; i<N; ++i)
	{
		if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
		for(int j=1,x; j<=cnt&&(x=i*P[j])<N; ++j)
		{
			Not_p[x]=1;
			if(i%P[j]) mu[x]=-mu[i], phi[x]=phi[i]*(P[j]-1);
			else {mu[x]=0, phi[x]=phi[i]*P[j]; break;}
		}
	}
	for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
inline LL Get_phi(int n){
	return n<N?phi[n]:sum[Max/n][0];
}
inline LL Get_mu(int n){
	return n<N?mu[n]:sum[Max/n][1];
}
void Calc(int n)
{
	if(n<N) return;
	if(vis[Max/n]) return;
	int t=Max/n;
	vis[t]=1, sum[t][0]=((LL)n+1)*n>>1, sum[t][1]=1;//n+1可能爆int!
	for(LL nxt,i=2; i<=n; i=nxt+1){
		nxt=n/(n/i), Calc(n/i);
		sum[t][0]-=Get_phi(n/i)*(nxt-i+1), sum[t][1]-=Get_mu(n/i)*(nxt-i+1);
	}
}

int main()
{
	Make_Table();
	int T; scanf("%d",&T);
	while(T--){
		memset(vis,0,sizeof vis);
		scanf("%d",&Max);
		if(Max<N) printf("%lld %lld\n",phi[Max],mu[Max]);//mu[]如果是int就不要用%lld。
		else Calc(Max),printf("%lld %lld\n",sum[1][0],sum[1][1]);
	}
	return 0;
}

朴素写法

//
//phi[]要longlong!
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=5e6;

int cnt,Max,P[N>>3],mu[N];
LL phi[N],sum[20005][2];
bool Not_p[N],vis[20005][2];

void Make_Table()
{
	mu[1]=phi[1]=1;
	for(int i=2; i<N; ++i)
	{
		if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
		for(int j=1; j<=cnt&&i*P[j]<N; ++j)
		{
			Not_p[i*P[j]]=1;
			if(i%P[j]) mu[i*P[j]]=-mu[i], phi[i*P[j]]=phi[i]*(P[j]-1);
			else {mu[i*P[j]]=0, phi[i*P[j]]=phi[i]*P[j]; break;}
		}
	}
	for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
LL Calc_p(LL n)//这的n为什么必须要开longlong(2147483647)?因为下边。。
{
	if(n<N) return phi[n];
	if(vis[Max/n][0]) return sum[Max/n][0];
	vis[Max/n][0]=1;
	LL res=1ll*n*((LL)n+1)>>1;//n+1可能爆int!
	for(LL nxt,i=2; i<=n; i=nxt+1)//nxt+1可能爆int
		nxt=n/(n/i), res-=Calc_p(n/i)*(nxt-i+1);
	return sum[Max/n][0]=res;
}
LL Calc_m(int n)
{
	if(n<N) return mu[n];
	if(vis[Max/n][1]) return sum[Max/n][1];
	vis[Max/n][1]=1;
	LL res=1;
	for(LL nxt,i=2; i<=n; i=nxt+1)
		nxt=n/(n/i), res-=Calc_m(n/i)*(nxt-i+1);
	return sum[Max/n][1]=res;
}

int main()
{
	Make_Table();
	int T,n; scanf("%d",&T);
	while(T--){
		memset(vis,0,sizeof vis);
		scanf("%d",&Max),printf("%lld %lld\n",Calc_p(Max),Calc_m(Max));
	}
	return 0;
}

map

洛谷上还行吧。。BZOJ成功T掉。

//phi[]要longlong!
#include <map>
#include <cstdio>
#include <algorithm>
typedef long long LL;
const int N=6e6;

int cnt,P[N>>3],mu[N];
LL phi[N];
bool Not_p[N];
std::map<int,LL> mp[2];
std::map<int,LL>::iterator it;

void Make_Table()
{
	mu[1]=phi[1]=1;
	for(int i=2; i<N; ++i)
	{
		if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
		for(int j=1; j<=cnt&&i*P[j]<N; ++j)
		{
			Not_p[i*P[j]]=1;
			if(i%P[j]) mu[i*P[j]]=-mu[i], phi[i*P[j]]=phi[i]*(P[j]-1);
			else {mu[i*P[j]]=0, phi[i*P[j]]=phi[i]*P[j]; break;}
		}
	}
	for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
LL Calc_p(LL n)//这的n为什么必须要开longlong(2147483647)?
{
	if(n<N) return phi[n];
	if((it=mp[0].find(n))!=mp[0].end()) return it->second;
	LL res=n*(n+1)>>1;
//	if(n&1) res=(n+1)/2*n;
//	else res=n/2*(n+1);
	for(LL nxt,i=2; i<=n; i=nxt+1)//nxt+1可能爆int
		nxt=n/(n/i), res-=Calc_p(n/i)*(nxt-i+1);
	return mp[0][n]=res;
}
LL Calc_m(int n)
{
	if(n<N) return mu[n];
	if((it=mp[1].find(n))!=mp[1].end()) return it->second;
	LL res=1;
	for(LL nxt,i=2; i<=n; i=nxt+1)
		nxt=n/(n/i), res-=Calc_m(n/i)*(nxt-i+1);
	return mp[1][n]=res;
}

int main()
{
	Make_Table();
	int T,n; scanf("%d",&T);
	while(T--)
		scanf("%d",&n),printf("%lld %lld\n",Calc_p(n),Calc_m(n));
	return 0;
}
posted @ 2018-04-03 20:31  SovietPower  阅读(266)  评论(1编辑  收藏  举报