【分治法 BFS 质因数分解】P12255 [蓝桥杯 2024 国 Java B] 园丁|普及+

【分治法 BFS 质因数分解】P12255 [蓝桥杯 2024 国 Java B] 园丁|普及+

本文涉及知识点

数论:质数、最大公约数、菲蜀定理
C++BFS算法

P12255 [蓝桥杯 2024 国 Java B] 园丁

题目描述

小明是一位尽职尽责的园丁。这天他负责维护一棵树,树上有 n n n 个结点 1 , 2 , … , n 1, 2, \ldots, n 1,2,…,n,根结点为 1 1 1,结点 i i i 的权值为 a i a_i ai​。他需要更改一些结点的权值为任意正整数,使得对于任意一个至少有 2 2 2 个儿子结点的结点 i i i 满足:任意两个 i i i 的儿子结点的权值的乘积都不是完全平方数。请问小明至少需要修改多少个结点的权值?

输入格式

输入共 n + 1 n+1 n+1 行。

第一行为一个正整数 n n n。

第二行为 n n n 个由空格分开的正整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1​,a2​,…,an​。

后面 n − 1 n-1 n−1 行,每行两个正整数表示树上的一条边。

输出格式

输出共 1 1 1 行,一个整数表示答案。

输入输出样例 #1

输入 #1

6 1 2 9 8 4 4 1 2 1 3 1 4 2 5 2 6 

输出 #1

2 

说明/提示

样例说明

其中一种方案:将结点 2 , 5 2, 5 2,5 的权值分别修改为 3 , 2 3, 2 3,2。

评测用例规模与约定

  • 对于 20 % 20\% 20% 的评测用例,保证 n ≤ 10 3 n \leq 10^3 n≤103。
  • 对于 100 % 100\% 100% 的评测用例,保证 1 ≤ n ≤ 10 5 1\leq n \leq 10^5 1≤n≤105, 1 ≤ a i ≤ 10 9 1 \leq a_i \leq 10^9 1≤ai​≤109。

P12255 [蓝桥杯 2024 国 Java B] 园丁

分治法:枚举cur的孩子。非兄弟节点,无影响。
性质一: X = x 1 × x 2 × x 2 , x × y 是否是完全平方数 ⟺ x 1 × y 是否是完全平方数 X=x1\times x2 \times x2,x \times y 是否是完全平方数 \iff x1 \times y 是否是完全平方数 X=x1×x2×x2,x×y是否是完全平方数⟺x1×y是否是完全平方数,f(x):如果x包括相同的因子x2,x/=(x2x2)。
性质二: x × y 是完全平方数,则 f ( x ) = = f ( y ) x \times y 是完全平方数,则f(x)==f(y) x×y是完全平方数,则f(x)==f(y)。
w[i]=f(w[i])。BFS或DFS求出各节点的孩子,依次处理。如果cur的孩子某个权重有c个,则ans += c-1。
时间复杂度:O(nsqrt(1e9)) 可以只枚举小于等于sqrt(1e9)的质数。理论上超时。实际上可以过。

代码

核心代码

#include<iostream>#include<sstream>#include<vector>#include<map>#include<unordered_map>#include<set>#include<unordered_set>#include<string>#include<algorithm>#include<functional>#include<queue>#include<stack>#include<iomanip>#include<numeric>#include<math.h>#include<climits>#include<assert.h>#include<cstring>#include<list>#include<array>#include<bitset>usingnamespace std;template<classT1,classT2> std::istream&operator>>(std::istream& in, pair<T1, T2>& pr){ in >> pr.first >> pr.second;return in;}template<classT1,classT2,classT3> std::istream&operator>>(std::istream& in, tuple<T1, T2, T3>& t){ in >>get<0>(t)>>get<1>(t)>>get<2>(t);return in;}template<classT1,classT2,classT3,classT4> std::istream&operator>>(std::istream& in, tuple<T1, T2, T3, T4>& t){ in >>get<0>(t)>>get<1>(t)>>get<2>(t)>>get<3>(t);return in;}template<classT1,classT2,classT3,classT4,classT5,classT6,classT7> std::istream&operator>>(std::istream& in, tuple<T1, T2, T3, T4,T5,T6,T7>& t){ in >>get<0>(t)>>get<1>(t)>>get<2>(t)>>get<3>(t)>>get<4>(t)>>get<5>(t)>>get<6>(t);return in;}template<classT=int> vector<T>Read(){int n; cin >> n; vector<T>ret(n);for(int i =0; i < n; i++){ cin >> ret[i];}return ret;}template<classT=int> vector<T>ReadNotNum(){ vector<T> ret; T tmp;while(cin >> tmp){ ret.emplace_back(tmp);if('\n'== cin.get()){break;}}return ret;}template<classT=int> vector<T>Read(int n){ vector<T>ret(n);for(int i =0; i < n; i++){ cin >> ret[i];}return ret;}template<int N =1'000'000>classCOutBuff{public:COutBuff(){ m_p = puffer;}template<classT>voidwrite(T x){int num[28], sp =0;if(x <0)*m_p++='-', x =-x;if(!x)*m_p++=48;while(x) num[++sp]= x %10, x /=10;while(sp)*m_p++= num[sp--]+48;AuotToFile();}voidwritestr(constchar* sz){strcpy(m_p, sz); m_p +=strlen(sz);AuotToFile();}inlinevoidwrite(char ch){*m_p++= ch;AuotToFile();}inlinevoidToFile(){fwrite(puffer,1, m_p - puffer,stdout); m_p = puffer;}~COutBuff(){ToFile();}private:inlinevoidAuotToFile(){if(m_p - puffer > N -100){ToFile();}}char puffer[N],* m_p;};template<int N =1'000'000>classCInBuff{public:inlineCInBuff(){}inline CInBuff<N>&operator>>(char& ch){FileToBuf();while(('\r'==*S)||('\n'==*S)||(' '==*S)){ S++;}//忽略空格和回车 ch =*S++;return*this;}inline CInBuff<N>&operator>>(int& val){FileToBuf();intx(0),f(0);while(!isdigit(*S)) f |=(*S++=='-');while(isdigit(*S)) x =(x <<1)+(x <<3)+(*S++^48); val = f ?-x : x; S++;//忽略空格换行 return*this;}inline CInBuff&operator>>(longlong& val){FileToBuf();longlongx(0);intf(0);while(!isdigit(*S)) f |=(*S++=='-');while(isdigit(*S)) x =(x <<1)+(x <<3)+(*S++^48); val = f ?-x : x; S++;//忽略空格换行return*this;}template<classT1,classT2>inline CInBuff&operator>>(pair<T1, T2>& val){*this>> val.first >> val.second;return*this;}template<classT1,classT2,classT3>inline CInBuff&operator>>(tuple<T1, T2, T3>& val){*this>>get<0>(val)>>get<1>(val)>>get<2>(val);return*this;}template<classT1,classT2,classT3,classT4>inline CInBuff&operator>>(tuple<T1, T2, T3, T4>& val){*this>>get<0>(val)>>get<1>(val)>>get<2>(val)>>get<3>(val);return*this;}template<classT=int>inline CInBuff&operator>>(vector<T>& val){int n;*this>> n; val.resize(n);for(int i =0; i < n; i++){*this>> val[i];}return*this;}template<classT=int> vector<T>Read(int n){ vector<T>ret(n);for(int i =0; i < n; i++){*this>> ret[i];}return ret;}template<classT=int> vector<T>Read(){ vector<T> ret;*this>> ret;return ret;}private:inlinevoidFileToBuf(){constint canRead = m_iWritePos -(S - buffer);if(canRead >=100){return;}if(m_bFinish){return;}for(int i =0; i < canRead; i++){ buffer[i]= S[i];//memcpy出错 } m_iWritePos = canRead; buffer[m_iWritePos]=0; S = buffer;int readCnt =fread(buffer + m_iWritePos,1, N - m_iWritePos,stdin);if(readCnt <=0){ m_bFinish =true;return;} m_iWritePos += readCnt; buffer[m_iWritePos]=0; S = buffer;}int m_iWritePos =0;bool m_bFinish =false;char buffer[N +10],* S = buffer;};template<classT=int>classCUniqueFactorization{public:CUniqueFactorization(T iPrime,int cnt){ m_data.emplace_back(iPrime, cnt);}CUniqueFactorization(vector<T> primes ={}, vector<int> cnts ={}){for(int i =0; i < primes.size(); i++){ m_data.emplace_back(primes[i], cnts[i]);}} CUniqueFactorization operator+(const CUniqueFactorization& o)const{returnAdd(o,true);} CUniqueFactorization Add(const CUniqueFactorization& o,bool bIgornZero =false)const{ CUniqueFactorization ret;int i =0, j =0;while((i < m_data.size())&&(j < o.m_data.size())){if(m_data[i].first == o.m_data[j].first){int cnt = m_data[i].second + o.m_data[j].second;if((0!= cnt)||!bIgornZero){ ret.m_data.emplace_back(m_data[i].first, cnt);} i++, j++;}elseif(m_data[i].first < o.m_data[j].first){ ret.m_data.emplace_back(m_data[i]); i++;}else{ ret.m_data.emplace_back(o.m_data[j]); j++;}} ret.m_data.insert(ret.m_data.end(), m_data.begin()+ i, m_data.end()); ret.m_data.insert(ret.m_data.end(), o.m_data.begin()+ j, o.m_data.end());return ret;} CUniqueFactorization negation()const{ CUniqueFactorization ret; ret =*this;for(auto&[i, cnt]: ret.m_data){ cnt *=-1;}return ret;} CUniqueFactorization GetValue(const CUniqueFactorization& o)const{ CUniqueFactorization ret;for(constauto&[pri, cnt]: m_data){ ret.m_data.emplace_back(pri,0);}return ret + o;}; pair<T, T>Union()const{longlong ll1 =1, ll2 =1;for(auto[pri, cnt]: m_data){auto& ll =(cnt >=0)? ll1 : ll2;for(int j =0; j <abs(cnt); j++){ ll *= pri;}//可以用快速指数幂加速}return{ ll1,ll2 };} vector<pair<T,int>> m_data;};classCCreatePrime{public:CCreatePrime(int iMax):m_isPrime(iMax +1,true){ m_isPrime[0]= m_isPrime[1]=false;for(int i =2; i <= iMax; i++){if(m_isPrime[i]){ m_vPrime.emplace_back(i);}for(constauto& n : m_vPrime){if((longlong)n * i > iMax){break;} m_isPrime[n * i]=false;if(0== i % n){break;}}}} vector<int> m_vPrime; vector<bool> m_isPrime;};template<classT=int>classCUniqueFactorizationFactory{public:CUniqueFactorizationFactory(T iMax):m_cc(sqrt(iMax)+2),m_vPrime(m_cc.m_vPrime){} CUniqueFactorization<T>Factorization(T x){ CUniqueFactorization<T> ret;for(constauto& iPre : m_vPrime){int cnt =0;while(0== x % iPre){ cnt++; x /= iPre;}if(cnt >0){ ret.m_data.emplace_back(iPre, cnt);}if(iPre * iPre > x){break;}}if(x >1){ ret.m_data.emplace_back(x,1);}return ret;}const vector<int>& m_vPrime;protected: CCreatePrime m_cc;};classCNeiBo{public:static vector<vector<int>>Two(int n,const vector<pair<int,int>>& edges,bool bDirect,int iBase =0){ vector<vector<int>>vNeiBo(n);for(constauto&[i1, i2]: edges){ vNeiBo[i1 - iBase].emplace_back(i2 - iBase);if(!bDirect){ vNeiBo[i2 - iBase].emplace_back(i1 - iBase);}}return vNeiBo;}static vector<vector<int>>Two(int n,const vector<vector<int>>& edges,bool bDirect,int iBase =0){ vector<vector<int>>vNeiBo(n);for(constauto& v : edges){ vNeiBo[v[0]- iBase].emplace_back(v[1]- iBase);if(!bDirect){ vNeiBo[v[1]- iBase].emplace_back(v[0]- iBase);}}return vNeiBo;}static vector<vector<std::pair<int,int>>>Three(int n, vector<vector<int>>& edges,bool bDirect,int iBase =0){ vector<vector<std::pair<int,int>>>vNeiBo(n);for(constauto& v : edges){ vNeiBo[v[0]- iBase].emplace_back(v[1]- iBase, v[2]);if(!bDirect){ vNeiBo[v[1]- iBase].emplace_back(v[0]- iBase, v[2]);}}return vNeiBo;}static vector<vector<std::pair<int,int>>>Three(int n,const vector<tuple<int,int,int>>& edges,bool bDirect,int iBase =0){ vector<vector<std::pair<int,int>>>vNeiBo(n);for(constauto&[u, v, w]: edges){ vNeiBo[u - iBase].emplace_back(v - iBase, w);if(!bDirect){ vNeiBo[v - iBase].emplace_back(u - iBase, w);}}return vNeiBo;}static vector<vector<int>>Mat(vector<vector<int>>& neiBoMat){ vector<vector<int>>neiBo(neiBoMat.size());for(int i =0; i < neiBoMat.size(); i++){for(int j = i +1; j < neiBoMat.size(); j++){if(neiBoMat[i][j]){ neiBo[i].emplace_back(j); neiBo[j].emplace_back(i);}}}return neiBo;}};classSolution{public:intAns(vector<int>& a, vector<pair<int,int>>& edge){static CUniqueFactorizationFactory uff(1000'000'000);for(auto& i : a){auto uf = uff.Factorization(i); i =1;for(constauto&[p, cnt]: uf.m_data){if(cnt &1){ i *= p;}}}auto neiBo =CNeiBo::Two(a.size(), edge,false,1); function<void(int,int)> DFS =[&](int cur,int par){ unordered_map<int,int> m;for(constauto& next : neiBo[cur]){if(next == par){continue;} m[a[next]]++;DFS(next, cur);}for(constauto&[tmp, cnt]: m){ m_ans +=(cnt -1);}};DFS(0,-1);return m_ans;}int m_ans =0;};intmain(){#ifdef_DEBUGfreopen("a.in","r",stdin);#endif// DEBUG  ios::sync_with_stdio(0); cin.tie(nullptr);//CInBuff<> in; COutBuff<10'000'000> ob;int N; cin >> N ;auto a =Read<int>(N);auto edge =Read<pair<int,int>>(N -1);#ifdef_DEBUG //printf("N=%d,K=%d", N,K);//Out(W, ",W=");Out(edge,",edge=");////Out(grid, ",grid=");Out(a,",a=");////Out(rr, ",rr=");// //Out(ab, ",ab=");// //Out(par, "par=");// //Out(que, "que=");// //Out(B, "B=");#endif// DEBUG auto res =Solution().Ans(a,edge); cout << res;return0;};

单元测试

vector<int> a; vector<pair<int,int>> edge;TEST_METHOD(TestMethod11){ edge ={{1,2},{1,3},{1,4},{2,5},{2,6}}, a ={1,2,9,8,4,4};auto res =Solution().Ans(a, edge);AssertEx(2, res);}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步ZEEKLOG学院,听白银讲师(也就是鄙人)的讲解。
https://edu.ZEEKLOG.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.ZEEKLOG.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

Read more

无人机电力设备智能巡检检测数据集 - 缺陷检测与分类 电力巡检设备状态检测数据集 铁塔顶部 - 电缆头部异物 - 爬电距离装置头部 - 开关头部 - 陶瓷绝缘子污秽 - 导线端头部

无人机电力设备智能巡检检测数据集 - 缺陷检测与分类 电力巡检设备状态检测数据集 铁塔顶部 - 电缆头部异物 - 爬电距离装置头部 - 开关头部 - 陶瓷绝缘子污秽 - 导线端头部

无人机电力巡检设备状态检测数据集,6056张,yolo,voc,coco标注方式、 图像尺寸:800*800 类别数量:49类 训练集图像数量:5292; 验证集图像数量:560; 测试集图像数量:204 类别名称: 每一类图像数 ,每一类标注数 csat_tt - 铁塔顶部:244, 254 ddan_tt_vatla - 电缆头部异物:173, 175 krang_tt - 爬电距离装置头部:142, 216 kdo_tt - 开关头部:44, 60 cdien_gom_ban - 陶瓷绝缘子污秽:58,

By Ne0inhk

从命令行到自动诊断:构建 AI 驱动的故障树与交互式排障机器人

从命令行到自动诊断:构建 AI 驱动的故障树与交互式排障机器人 引言 在网络行业,故障是永恒的主题。 但令人困惑的是:即便企业投入巨额预算堆设备、做双活、上可视化系统,只要遇到真正棘手的事故,大家最后还是回到命令行,靠工程师的直觉、经验和试探式验证步骤,一步步往前摸。 而现在的问题是:网络的复杂度远远超过了人脑能同时处理的规模。多协议叠加、遥测爆炸式增长、变化越来越频繁……传统的“工程师 + CLI”的模式正在变成瓶颈。 这篇文章,我要把“工程师思路的自动化”写成一套真正可以落地的体系:故障树、证据链、主动探测、对话式诊断机器人,以及自动修复流水线。 它不是让 AI 取代工程师,而是把工程师最有价值的地方提炼出来,做成可复用、可审计、可回放、可持续改进的系统。 文章的结构基于我在企业网络、数据中心和运营商环境里做过多个“自动诊断 / 自动修复”项目的经验整理,目标明确:你照着文章,就能推动一个能跑的

By Ne0inhk
深度解析英伟达最新“瓦力”机器人:物理AI时代的开发者红利与技术突破

深度解析英伟达最新“瓦力”机器人:物理AI时代的开发者红利与技术突破

2026年CES展会上,黄仁勋牵着那款酷似《机器人总动员》“瓦力”的Reachy Mini机器人完成流畅互动时,全场的欢呼不仅是对萌系设计的认可,更是对一个新时代的致敬——英伟达用这套全新机器人系统,正式宣告物理AI从实验室走向产业化。对于咱们ZEEKLOG的开发者而言,这波技术浪潮带来的不只是视觉震撼,更是可落地的开发工具、开源生态和商业机遇。今天就从技术内核、开发价值、行业对比三个维度,深度拆解英伟达最新机器人的核心竞争力,帮大家找准入局切入点。 一、不止“萌出圈”:英伟达新机器人的技术内核拆解 很多人被“瓦力”的外形圈粉,但真正让行业震动的是其背后的全栈技术体系。不同于传统机器人“硬件堆砌+单一功能编程”的模式,英伟达这套系统是“大脑-身体-训练场”的全链路协同,每一个环节都为开发者预留了创新空间。 1. 核心大脑:GR00T N1.6模型的双系统突破 作为全球首个开源人形机器人基础模型,最新的Isaac GR00T N1.6堪称“机器人界的GPT-4o”,其最核心的创新是双系统架构设计,完美复刻了人类“本能反应+深度思考”

By Ne0inhk

OpenClaw基础-3-telegram机器人配置与加入群聊

OpenClaw基础-3-telegram机器人配置与加入群聊 💡 大家好,我是可夫小子,《小白玩转ChatGPT》专栏作者,关注AI编程、AI自动化和自媒体。 Openclaw的优势是接入各种聊天工作,在前面的文章里,已经介绍了如何接入飞书。但之前我也提到了,飞书的最大的问题是请求多的限制,以及无法在非认证企业账号下面组建群聊。但这些限制另一个聊天工具可以打破,那就是Telegram,今天就跟大家分享一下,如果在OpenClaw里面接入Telegram。 第一步:Openclaw端配置 通过命令openclaw config,local→channels→telegrams 这里等待输入API Token,接下来我们去Telegram里面获取 第二步:Telegram端配置 1. 1. 在聊天窗口找到BotFather,打开对话与他私聊 2. 3. 然后再输入一个机器人,再输入一个账号名username,这里面要求以Bot或者Bot结尾,这个是全网的id,要 2. /newbot 来创建一个机器人,输入一个名字name

By Ne0inhk