zoukankan      html  css  js  c++  java
  • CF1139D Steps to One

    CF1139D Steps to One

    这,暴力写了2h还没写出来,正解写了10min就一遍AC了

    话说我没想到 (1)(n) 中的因数总数是 (O(nln n)) 级别是不是该被毙掉啊

    暴力

    首先设个 (dp_i) 表示当前 (gcd)(i) ,需要 (dp_i) 次变成 (1)

    (ans=1+dfrac{sum_{i=1}^{m}dp_i}{m})

    前面那个 (1) 只要自己打个暴力就很好理解了,因为一开始没有数。

    如果你不知道为啥这么设,多试几次就知道这么设有种能往下推的感觉

    发现如果连边 (i o factor_i) 是个 (DAG) ,那么模拟建反图从 (1) 往上转移可得 (dp_i=1+dfrac{sum_{j=1}^{m}dp[gcd(i,j)]}{m})

    然后我决定写个暴力验证一下,然后一调就是2h。因为右边也有 (dp_i) ,所以要把右边 (dfrac{m}{i})(dp_i) 移过来。

    这就是暴力唯一的价值

    正解

    既然都要移过来了,那还不如推正解。

    [sum_{i=1}^{m}dp[gcd(i,k)]\ =sum_{d|k}dp[d]sum_{i=1}^{m}[gcd(i,k)==d]\ =sum_{d|k}dp[d]sum_{i=1}^{frac{m}{d}}[gcd(i,dfrac{k}{d})==1]\ =sum_{d|k}dp[d]sum_{i=1}^{frac{m}{d}}sum_{t|gcd(i,frac{k}{d})}mu(t)\ =sum_{d|k}dp[d]sum_{t|frac{k}{d}}mu(t)lfloordfrac{m}{dt} floor\ =sum_{T|k}dfrac{m}{T}sum_{d|T}dp[d]mu(dfrac{T}{d}) ]

    带回去:

    [dp[i]=1+dfrac{sum_{T|i}dfrac{m}{T}sum_{d|T}dp[d]*mu(dfrac{T}{d})}{m} ]

    然后把那几个 (dp_i) 提出来移过去

    [dp[i]=1+dfrac{sum_{T|i}dfrac{m}{T}sum_{d|T,d<i}dp[d]*mu(dfrac{T}{d})}{m}+dfrac{lfloordfrac{m}{i} floor dp[i]}{m}\ (m-dfrac{m}{i})dp[i]=m+sum_{T|i}dfrac{m}{T}sum_{d|T,d<i}dp[d]*mu(dfrac{T}{d})\ dp[i]=dfrac{m+sum_{T|i}dfrac{m}{T}sum_{d|T,d<i}dp[d]*mu(dfrac{T}{d})}{m-dfrac{m}{i}} ]

    维护 (f_T=sum_{d|T}dp[d]*mu(dfrac{T}{d}))

    发现只要先更新 (dp) 再更新 (f) 就可以避开 (d<i) 这个奇怪的东西了

    考虑如何快速更新 (f) ,我们发现只要枚举 (i|T) ,修改所有 (T) 那么均摊下来总复杂度是 (sum_{i=1}^{n}dfrac{n}{i}=nln n)

    然后就是我傻逼的地方了,总因数个数也是 (O(nln n)) 级别的,直接预处理出来即可

    复杂度 (O(nln n))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef double db;
    #define mkp(x,y) make_pair(x,y)
    #define fi first
    #define se second
    #define pb(x) push_back(x)
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    	return f?x:-x;
    }
    #define N 100005
    #define mod 1000000007
    int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*res*n%mod;return res;}
    void fmod(int&x){x+=x>>31&mod,x-=mod,x+=x>>31&mod;}
    int m,mu[N],pri[N],cnt,f[N],dp[N],inv[N],ans;
    bool vis[N];
    vector<int>d[N];
    void Sieve(const int&K){
    	mu[1]=1;
    	for(int i=2;i<=K;++i){
    		if(!vis[i])mu[i]=-1,pri[++cnt]=i;
    		for(int j=1;i*pri[j]<=K;++j){
    			vis[i*pri[j]]=1;
    			if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
    			mu[i*pri[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=K;++i)
    		for(int j=1;i*j<=K;++j)
    			d[i*j].pb(i);
    	inv[1]=1;
    	for(int i=2;i<=K;++i)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    }
    signed main(){
    	cin>>m,Sieve(m);
    	dp[1]=0;
    	for(int i=2;i<=m;++i){
    		int res=m;
    		for(int j:d[i])
    			fmod(res+=1ll*(m/j)*f[j]%mod);
    		dp[i]=1ll*res*inv[m-m/i]%mod;
    		for(int j=1;i*j<=m;++j)
    			fmod(f[i*j]+=dp[i]*mu[j]);
    	}
    	ans=m;
    	for(int i=1;i<=m;++i)fmod(ans+=dp[i]);
    	printf("%lld
    ",1ll*ans*inv[m]%mod);
    	return 0;
    }
    

    (color{black}{ exttt{F}}color{red}{ exttt{orever_Pursuit}}) 10min就秒了这题,还是 (O(n)) 的,我被吊打了/ll

  • 相关阅读:
    Mybatis专栏文章整理成册《Mybatis进阶》!!!
    Mybatis的几种传参方式,你了解吗?
    HDU 1890
    POJ 2186
    HDU 2896
    POJ 1322
    POJ 1276
    POJ 1208
    POJ 1189
    POJ 1178
  • 原文地址:https://www.cnblogs.com/zzctommy/p/13904323.html
Copyright © 2011-2022 走看看