HDU -- 6069 Counting Divisors 【思维 + 二次筛法】多校第四场1003

xiaoxiao2021-02-27  172

传送门 //题意就不说了. //思路:首先这个应该可以推到. 所以可以发现这个k次方是没有什么影响的, 还是直接求质因子连乘就是了. //问题的关键在于如何在可行的复杂度中求出区间中每一个数的质因子连乘的幂. n√n的复杂度绝对不行, 所以我们选用类似于区间筛的方法处理. 这样复杂度就大约在nlogn, 因为这个是区间求质因子个数, 与单数求质因子个数肯定不同赛.

AC Code

/** @Cain*/ const ll mod = 998244353; const int maxn=1e6+5; ll L,R,k; bool ispri[maxn]; ll pri[maxn]; ll p; void sieve() //预处理1e6以内的素数,连乘也够了. { Fill(ispri,true); ispri[0] = ispri[1] = false; p = 0; for(ll i=2;i<maxn;i++){ if(ispri[i]){ pri[p++] = i; for(ll j=i*2;j<maxn;j+=i){ ispri[j] = false; } } } } ll f[maxn], cnt[maxn]; //f保存当前这个值(也用来判断幂),cnt是每一个数的方案数. void solve() { scanf("%lld %lld %lld",&L,&R,&k); ll res = 0; for(int i=0;i<=R-L;i++) f[i] = L+i,cnt[i] = 1; for(ll i=0; i<p && pri[i]*pri[i] <= R ; i++){ ll tmp = L; //假设从L开始扫 if(L % pri[i]) tmp = (L/pri[i]+1)*pri[i]; //如果当前这个素数不是因子就从最近的开始枚举. //否则一个数会被多次算入. for(ll j=tmp;j<=R;j+= pri[i]){ ll ans = 0; //将L-R所有的可以被当前pri[i]除尽的数筛掉. while(f[j-L] % pri[i] == 0){ f[j-L] /= pri[i]; ans++; //算幂. } cnt[j-L] = cnt[j-L]*(k*ans+1) % mod; //保存方案数 } } for(int i=0;i<=R-L;i++){ if(f[i] != 1) res = (res + cnt[i]*(k+1) ) % mod; //如果当前知不是1,表示最后一次除完还剩一个较大的素数. //所以次数需要再乘一下. else res = (res + cnt[i]) % mod; //否则就是被除尽的了, 剩下1不用管. } printf("%lld\n",res); }
转载请注明原文地址: https://www.6miu.com/read-12701.html

最新回复(0)