P9836 种树 题解
前言废话:不怎么打洛谷的比赛,昨天心血来潮,结果只看了 T1 且分配指数假了,或者说根本没深入思考,这下掉大分了。但个人感觉是很不错的题。
题意:给你一个序列 \(a\),并给你一个数 \(k\)。可以将其分解因数后乘到任意 \(a_i\) 上。求最大化的 \(a_i\) 因数个数的乘积。
看到因数个数不难想到质因数分解,分解后的质因子对因数个数的贡献是独立的。不难得到一个数的因数个数为:\(\displaystyle\prod_{i=1}^{n}(p_i+1)\) ,其中 \(p_i\) 为该数的质因子。
于是问题转换为:给长度为 \(n\) 的序列 \(a\) 和一个操作数 \(w\),每次操作可以使任意一个 \(a_i+1 \to a_i\)。可以重复选择同一位置,最多进行 \(k\) 次该操作。最大化 \(\displaystyle\prod_{i=1}^{n} a_i\)。
这是一个经典的贪心问题。我找到了他在力扣上的题目。容易证明每次操作最小值是最优的。
证明:用 \(x,y(x\ge y)\) 来表示两个元素。
对于较大元素操作后的乘积为 \((x+1)y=xy+y\) 而对较小元素操作后的乘积为 \(x(y+1)=xy+x\)。两者相减得到 \(xy+y-xy-x=y-x\le0\),因此选择较小元素操作后的乘积更大。
最后由于 \(n\le1e4\) 所以怎么实现都行。虽然丑但相信大家能看懂我写的码,这个复杂度是 \(O(n\sqrt{n}\log{n})\)。
这是我非常抽象且丑陋的码。问就是不想重构导致的。有空会重构一份的。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e4+5;
const int M=2e3+5;
const ll mod=998244353;
ll ans=1;
ll a[N];
int n,m;
int tong[N],vis[N],sum,r[N];
int ysm[110],cntm[N],pm;
int ys[N][110],p[N];
priority_queue<int>cnt[M];
void fj(int k,int x){
int q=sqrt(x),y=x;
for(int i=2;i<=q;i++){
if(y%i==0){
if(!vis[i]){
vis[i]=1;
tong[i]=++sum;
r[sum]=i;
}
ys[k][++p[k]]=i;
int tot=0;
while(y%i==0){
y/=i;
tot++;
}
cnt[tong[i]].push(-tot);
}
if(y==1) break;
}
if(y>1){
ys[k][++p[k]]=y;
if(!vis[y]){
vis[y]=1;
tong[y]=++sum;
r[sum]=y;
}
cnt[tong[y]].push(-1);
}
}
void fj2(){
int q=sqrt(m),y=m;
for(int i=2;i<=q;i++){
if(y%i==0){
if(!vis[i]){
vis[i]=1;
tong[i]=++sum;
r[sum]=i;
}
ysm[++pm]=i;
while(y%i==0){
y/=i;
cntm[tong[i]]++;
}
}
if(y==1) break;
}
if(y>1){
ysm[++pm]=y;
if(!vis[y]){
vis[y]=1;
tong[y]=++sum;
r[sum]=y;
}
cntm[tong[y]]=1;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
fj(i,a[i]);
}
fj2();
for(int i=1;i<=sum;i++){
int x=cnt[tong[r[i]]].size();
for(int j=x;j<n;j++) cnt[tong[r[i]]].push(0);
}
for(int i=1;i<=pm;i++){
int t=ysm[i];
for(int j=1;j<=cntm[tong[t]];j++){
int x=cnt[tong[t]].top();
cnt[tong[t]].pop();
x--;
cnt[tong[t]].push(x);
}
}
for(int i=1;i<=sum;i++)
while(cnt[tong[r[i]]].size()){
int x=-cnt[tong[r[i]]].top();
cnt[tong[r[i]]].pop();
ans=(ans*(x+1))%mod;
}
printf("%lld",ans);
return 0;
}