zoukankan      html  css  js  c++  java
  • Codeforces 870F

    Codeforces 题目传送门 & 洛谷题目传送门

    首先考虑 (d(u,v)) 是个什么东西,分情况讨论:

    • (u otperp v)(d(u,v)=1)
    • (uperp v),记 (p_u)(u) 的最小质因子,(p_v)(v) 的最小质因子,那么继续分情况讨论:
      • (p_up_vle n)(d(u,v)=2)(u o p_up_v o v)
      • (p_up_v>n)(max(p_u,p_v)ledfrac{n}{2})(d(u,v)=3)(u o 2p_u o 2p_v o v)
      • (p_up_v>n)(max(p_u,p_v)>dfrac{n}{2})(d(u,v)=0)

    考虑对这四种情况分别计算,对于 (d(u,v)=1) 显然预处理出欧拉函数即可处理,即 (dbinom{n-1}{2}-sumlimits_{i=1}^n(varphi(i)-1))(由于 (1) 不能与任何点连边,因此 (d(u,v) e 0) 的点只可能在另外 (n-1) 个点之间),对于 (d(u,v)=2) 的情况直接处理比较困难,因此考虑正难则反,拿总方案数减去另外三种情况的方案数即可计算,对于第三种情况,由于 (p_up_v>0),因此在 ([1,n]) 中不存在某个数既是 (p_u) 也是 (p_v) 的倍数,因此对于某个固定的 (p_u,p_v),合法的 (u,v) 的对数即是 ([1,n])(p_x=p_u)(x) 的个数与 ([1,n])(p_x=p_v)(x) 的个数之积。我们不妨假设 (p_u<p_v),我们记 (cnt_x) 表示 ([1,n]) 中有多少个数最小质因子为 (x),那么考虑枚举 (p_u),合法的 (p_v) 必然在区间 ((max(p_u,dfrac{n}{p_u}),dfrac{n}{2}]) 之间,前缀和优化一下即可。对于第四种情况也同理,枚举 (p_u),合法的 (p_v) 在区间 ((max(i,dfrac{n}{2}),n]) 之间。第二种情况减一下即可,复杂度线性。

    最后讲一下我翻车的现场,我是考虑求出分别求出 (d(u,v)=1/2/3) 的情况并将它们的贡献加起来,(d(u,v)=1,3) 的情况自然是很容易求得的,但是 (d(u,v)=2) 的情况不好计算,然后我就一直在分析如何计算这种情况的方案数,xtbz……看来以后对于计算方案数的问题,如果正面计算比较困难要学会正难则反,学到了学到了(

    const int MAXN=1e7;
    int n,pr[MAXN/10+5],prcnt=0,mnp[MAXN+5],phi[MAXN+5],cnt[MAXN+5];
    bitset<MAXN+5> vis;
    void sieve(){
    	phi[1]=1;
    	for(int i=2;i<=n;i++){
    		if(!vis.test(i)){pr[++prcnt]=i;phi[i]=i-1;mnp[i]=i;}
    		for(int j=1;pr[j]*i<=n&&j<=prcnt;j++){
    			vis[pr[j]*i]=1;mnp[pr[j]*i]=pr[j];
    			if(i%pr[j]==0){phi[pr[j]*i]=phi[i]*pr[j];break;}
    			else phi[pr[j]*i]=phi[i]*phi[pr[j]];
    		}
    	}
    }
    int calc(int l,int r){return (l>r)?0:(cnt[r]-cnt[l]);}
    int main(){
    	scanf("%d",&n);sieve();ll sum=0,ans0=0,ans1=0,ans2=0,ans3=0;
    	for(int i=2;i<=n;i++) cnt[mnp[i]]++;
    	for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
    	for(int i=1;i<=n;i++) sum+=phi[i]-1;
    	ans1=1ll*(n-1)*(n-2)/2-sum;
    	for(int i=1;i<=n;i++){
    		int num=cnt[i]-cnt[i-1];
    		if(i<=n/2) ans3+=1ll*num*calc(max(i,n/i),n/2);
    		ans0+=1ll*num*calc(max(n/2,i),n);
    	} ans2=sum-ans0-ans3;
    	printf("%lld
    ",ans1+(ans2<<1)+(ans3<<1)+ans3);
    	return 0;
    }
    
  • 相关阅读:
    使用postman做接口测试(三)
    使用postman做接口测试(二)
    使用postman做接口测试(一)
    RobotFramework安装扩展库包autoitlibrary(四)
    RobotFramework安装扩展库包Selenium2Library(三)
    记录.gitattributes 设置合并时使用本地文件无效的解决方案
    golang 踩坑日记
    linux常用命令记录
    vim配置文件
    mysql case when记录
  • 原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-870F.html
Copyright © 2011-2022 走看看