首页 > 其他分享 >P9836 种树 题解

P9836 种树 题解

时间:2023-11-11 20:56:35浏览次数:37  
标签:pr cnt ++ 题解 ll while 种树 sum P9836

蒟蒻在考场上花了 2h45min AC 本题

通过高度求宽度

定义一棵树的宽度为它高度的正因数个数

我们可以预处理 \(10^4\) 之内素数。

	for(ll i=2; i<=10000; i++) {
		if(ok[i]==0) {
			ok[i]=i;
			pr[++nP]=i;
		}
		for(ll j=1; i*pr[j]<=10000&&j<=nP; j++) {
			ok[i*pr[j]]=pr[j];
		}
	}

然后对树的高度分解质因数,即可求出树的宽度。

ll findwidth(ll x,ll in){
	if(x==1) return 1;
	ll cnt=1,j=1,i=1;
	while(x>1){
		ll sum=0;
		while(x%pr[j]!=0){
			j++;
		}
		while(x%pr[j]==0){
			x/=pr[j];
			sum++;
		}
		nums[in][i]=(yin){pr[j],sum};
		cnt*=(sum+1);
		j++;
		i++;
	}
	return cnt;
}

测试点 1~10

\(w=1\)

此时相当于没有化肥可以施,直接用原高度求原宽度并相乘即可。

测试点 11~15

\(n=1\)

此时相当于只有一棵树可以施肥,直接用原高度乘以化肥求宽度即可。

AC解法

我们对于 \(w\) 分解质因数,随后一一枚举,针对每一个质因数遍历 \(n\) 棵树。

以枚举到质因数 \(x\),第 \(y\) 棵树,且这棵树的高度 \(=x^p \times z (z\in Z , z \bmod x > 0)\) 为例。

若在此施肥,可以使答案乘上 \(\frac{p+2}{p+1}\),容易发现,p 越小,这次施肥对答案贡献越大。

因此我们遍历得到 p 的最小值及它的位置,更新它的高度和宽度,重复操作,即可以得到最大答案。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=10009;
const ll MOD=998244353;
const ll INF=1e9+9;
ll n,w,p[N],pr[N],ok[N];
ll nP,ans=1;
struct yin{
	ll pr,num;
} nums[N][109];
ll sssm[N];

void input(){
	cin>>n>>w;
	for(ll i=1;i<=n;i++) cin>>p[i];
	for(ll i=2;i<=10000;i++){
		if(ok[i]==0){
			ok[i]=i;
			pr[++nP]=i;
		}
		for(ll j=1;i*pr[j]<=10000&&j<=nP;j++){
			ok[i*pr[j]]=pr[j];
		}
	}
}

ll findwidth(ll x,ll in) {
	if(x==1) return 1;
	ll cnt=1,j=1,i=1;
	while(x>1){
		ll sum=0;
		while(x%pr[j]!=0){
			j++;
		}
		while(x%pr[j]==0){
			x/=pr[j];
			sum++;
		}
		nums[in][i]=(yin){pr[j],sum};
		cnt*=(sum+1);
		j++;
		i++;
	}
	return cnt;
}

void solvew1(){ //即不能增加
	for(ll i=1;i<=n;i++){
		(ans*=findwidth(p[i],1))%=MOD;
	}
	cout<<ans;
}

void solven1(){ //即只能加在一棵树上
	cout<<findwidth(p[1]*w,1);
}

void solve(){
	for(ll i=1;i<=n;i++){
		sssm[i]=findwidth(p[i],i);
	}
	ll j=1;
	while(w>1){
		while(w%pr[j]!=0){
			j++;
		}
		if(w%pr[j]==0){
			w/=pr[j];
		}
		ll mx=INF,nmx=0;
		for(ll i=1;i<=n;i++){
			if(p[i]%pr[j]!=0) {
				mx=min(mx,1ll);
				if(mx==1) nmx=i;
				break;
			}
			else{
				ll k;
				for(k=1;;k++) {
					if(nums[i][k].pr==pr[j]) break;
				}
				mx=min(mx,nums[i][k].num+1);
				if(mx==nums[i][k].num+1) nmx=i;
			}
		}
		sssm[nmx]=sssm[nmx]/mx*(mx+1);
		if(mx==1){
			p[nmx]*=pr[j];
			ll k;
			for(k=1;;k++){
				if(nums[nmx][k].pr==0) break;
			}
			nums[nmx][k]=(yin){pr[j],1};
		}
		else{
			ll k;
			for(k=1;;k++) {
				if(nums[nmx][k].pr==pr[j]) break;
			}
			nums[nmx][k].num++;
		}
	}
	for(ll i=1;i<=n;i++) {
		(ans*=sssm[i]%MOD)%=MOD;
	}
	cout<<ans%MOD;
}

int main(){
	input();
	if(w==1)
		solvew1();
	else if(n==1)
		solven1();
	else
		solve();
	return 0;
}

有问题欢迎提出。

标签:pr,cnt,++,题解,ll,while,种树,sum,P9836
From: https://www.cnblogs.com/lemon-cyy/p/17826343.html

相关文章

  • [题解] CF1327F AND Segments
    ANDSegments有\(m\)个限制\((l,r,x)\)。要计算满足以下条件的长度为\(n\)的序列\(a\)的数量:\(\foralli\in[1,n],0\lea_i<2^k\)。\(\foralli\in[1,m],a_{l_i}\operatorname{and}a_{l_i+1}\operatorname{and}\cdots\operatorname{and}a_{r......
  • NOIP2023模拟赛 种树
    NOIP2023模拟赛种树先整无脑爆搜#include<iostream>#include<algorithm>#include<cstdio>#definemod%998244353#definelllonglongconstintN=1e4+10;usingnamespacestd;lln,w;llp[N];llfy[N],nfy;llans=-1;intvis[N];intge......
  • 【洛谷 P1035】[NOIP2002 普及组] 级数求和 题解(循环)
    [NOIP2002普及组]级数求和题目描述已知:。显然对于任意一个整数,当足够大的时候,。现给出一个整数,要求计算出一个最小的,使得。输入格式一个正整数。输出格式一个正整数。样例#1样例输入#11样例输出#12提示【数据范围】对于的数据,。【题目来源】NOIP2002普及组第一题......
  • AT_agc057_e 题解
    AT_agc057_e[0]约定\(r_i=\sum\limits_{j=1}^{m}[A_{i,j}\lek]\)\(r^{'}_i=\sum\limits_{j=1}^{m}[B_{i,j}\lek]\)\(c_j=\sum\limits_{i=1}^{n}[A_{i,j}\lek]\)\(c^{'}_j=\sum\limits_{i=1}^{n}[B_{i,j}\lek]\)[1]......
  • [题解] AT_dp_w Intervals
    Intervals有\(m\)条形如\((l,r,a)\)的限制,表示如果\(s_{[l,r]}\)中有1就会有\(a\)的价值。你要求长度为\(n\)的01串的价值的最大值。\(n,m\le2\times10^5\)。将每个限制挂到右端点上,在右端点处计算贡献。然后我们就只关心最后一个1出现的位置了。......
  • 转 问题解决:记录一次Linux服务器根目录突然爆满
    一般跟目录满了,可以重点关注/var这个目录 一、出问题了过了个双休来到公司,同时发现Linux终端的服务器状态中根目录空间直接爆满100%,周五走之前根目录仅仅使用了59%,同时项目服务的后台不停的有日志打印,而且测试的小伙伴说系统登录不上去了。下面记录一下个人排查并解决这个问题......
  • CF1485F Copy or Prefix Sum 题解
    思路考虑\(a_i\)要么是\(b_i\)要么是\(b_i-s\)。考虑\(s\)代表着什么。它是\(a\)的前缀和。那么必然是往前一段\(b\)的和。因为每个\(b\)代表着要么是这一位的\(a\)或者前面所有的\(a\)。考虑设\(f_i\)为这个位置填\(b_i\)的方案数。\(g_i\)为这个......
  • [POI2011] SMI-Garbage 题解
    题目链接显然,对于初始颜色与目标颜色不同的边,我们需要走过奇数次;对于初始颜色与目标颜色相同的边,我们需要走过偶数次。对于只有偶数边的情况,这种情况下不走就行;对于只有奇数边;可以理解为每条边只能经过一次,就是欧拉路径问题,并且考虑这题的特殊性质,如果一个图是由若干个简单环构......
  • CSP-S2019 江西 题解
    为什么有\(5\)道题?[CSP-S2019江西]和积和简单化一下式子:\[(n+1)\times\sumA_i\timesB_i-(\sumA_i)\times(\sumB_i)\]其中\(A,B\)都是前缀和。[CSP-S2019江西]网格图naive的kruskal是很naive的,所以需要一点简单的优化。考虑其本质过程就是按照......
  • CF1485E Move and Swap 题解
    不要什么脑子的带\(log\)做法。思路考虑\(dp_{i,j}\)表示红点到\(i\),蓝点到\(j\)的最大权值。那么有:\[dp_{i,j}=\max(dp_{fa_i,pre},dp_{fa_j,pre})+|a_i-a_j|\]其中\(pre\)是任意一个上一层节点。发现第二维没有用。可以优化:\[dp_i=\max(dp_{fa_i}+\max(|a_i-a_......