题解 P7704【「MCOI-09」Greedy Deletion】

$\text{Link}$

题意

有一个集合 $S_n=\{x|x\in\Bbb{N}_+,x\le n\}$,其权值为 $\prod_{i\in S_n}i$,从集合中删除一数 $x$ 的代价为 $x^k$,若要将其权值变为完全平方数,求最小代价。对 $998244353$ 取模。多组数据。

$T\le5\times10^5$,$1\le n\le\max n\le5\times 10^6$,$0\le k<998244353$

思路

先吐槽一下,这题大概应该放在 T3 的位置...

我们发现完全平方数仅要求其所有质因子的指数为 $1$,所以只删质因数定能将其变为完全平方数。

又因 $a,b,k\ge 2$ 时 $a^k+b^k\le a^kb^k$,所以只删质因数的代价是最少的。

算法 1

可以离线询问,排序,然后对于排完序后的 $n'_i$,将 $n'_{i-1}+1$ 至 $n'_i$ 之间的数分解质因数,算其贡献,最后对询问进行前缀和即可。

时间复杂度 $O(n^{\frac 5 4}+n\log\log n\log \text{mod}+T\log T)$,期望得分 $44$ 分。

算法 2

考虑筛出 $n$ 以内质数的所有倍数,在倍数处计算前缀和贡献,可以使用前向星将质数与其倍数之间连边,将倍数从 $1$ 扫到 $\max n$,再统计是加入 $i^k$ 的贡献还是 $-i^k$ 的贡献。注意,为了防止带上 $\log \bmod$,质数的 $k$ 次幂可以提前预处理。

时间复杂度 $O(n\log\log n+T)$,期望得分 $100$ 分。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=5e6+10,mod=998244353;
int maxn,k,T,anss[N],qp[N];
ll cur;
bool app[N];
inline int qpow(int x,int y){
    int res=1;
    while(y){
        if(y&1) res=1ll*res*x%mod;
        x=1ll*x*x%mod;
        y>>=1;
    }
    return res;
}
bitset<N>p;
int pri[N],cnt;
int head[N],cntg;
struct Edge{
    int to,nxt;
}a[N<<2];
inline void add(int u,int v){
    cntg++;
    a[cntg].to=v;
    a[cntg].nxt=head[u];
    head[u]=cntg;
}
inline void sieve(int n){
    p[1]=1;
    for(int i=2;i<=n;i++){
        if(!p[i]){
            pri[++cnt]=i;
            qp[cnt]=qpow(i,k);
            for(ll j=i;j<=n;j*=i)
                for(int q=j;q<=n;q+=j)
                    app[q]^=1;
            for(int j=i;j<=n;j+=i)
                if(app[j])
                    add(j,cnt),app[j]=0;
        }
        for(int j=1;j<=cnt&&i*pri[j]<=n;j++){
            p[i*pri[j]]=1;
            if(i%pri[j]==0)
                break;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=head[i];j;j=a[j].nxt)
            cur+=((app[a[j].to]^=1)?qp[a[j].to]:mod-qp[a[j].to]);
        anss[i]=cur%mod;
    }
}
int main(){
    T=read(),k=read(),maxn=read();
    sieve(maxn);
    while(T--){
        int n=read();
        write(anss[n]);
        putc('\n');
    }
    flush();
}

再见 qwq~

posted @ 2021-07-09 08:57  ffffyc  阅读(20)  评论(0)    收藏  举报  来源