NOIP训练 友好国度(点分治+容斥)

本文介绍了一种结合点分治与容斥原理解决特定问题的算法思路,并提供了详细的实现代码。通过分解质因数并计算贡献来求解每个因数的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门
思路:
直接上点分治+容斥计算每个因数对应的贡献即可。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
typedef long long ll;
const int N=1e5+5;
vector<int>e[N],fac[N],coe[N];
int n,a[N],lim=0,all,mx,siz[N],rt,Tim[N],cnt[N],mul[N],tim=0;
bool vis[N],chk[N];
ll ans=0;
inline int get(int x){
	if(mul[x])return mul[x];
	if(x<2)return mul[x]=x;
	int ret=1;
	for(ri i=0;i<fac[x].size();++i)ret*=fac[x][i];
	return mul[x]=ret;
}
inline void get_coef(int pos,int mul,int a){
	if(pos==fac[a].size()){if(~mul)coe[a].push_back(mul);return;}
	get_coef(pos+1,mul,a);
	get_coef(pos+1,-fac[a][pos]*mul,a);
}
inline void init(){
	for(ri i=2;i<=lim;++i)if(!vis[i])for(ri j=i;j<=lim;j+=i)vis[j]=1,fac[j].push_back(i);
	for(ri i=1,x;i<=n;++i)vis[i]=0,a[i]=get(a[i]);
}
void getroot(int p,int fa){
	siz[p]=1;
	int ms=0;
	for(ri i=0,v;i<e[p].size();++i){
		if((v=e[p][i])==fa||vis[v])continue;
		getroot(v,p),siz[p]+=siz[v],ms=max(ms,siz[v]);
	}
	ms=max(ms,all-siz[p]);
	if(ms<=mx)rt=p,mx=ms;
}
inline int query(int x){return Tim[x]==tim?cnt[x]:0;}
inline int ask(int x){
	int ret=0;
	if(!chk[x])get_coef(0,-1,x),chk[x]=1;
	for(ri i=0;i<coe[x].size();++i)ret+=coe[x][i]/abs(coe[x][i])*query(abs(coe[x][i]));
	return ret;
}
inline void update(int x){Tim[x]==tim?++cnt[x]:cnt[x]=1,Tim[x]=tim;}
inline void change(int x){
	if(!chk[x])get_coef(0,-1,x),chk[x]=1;
	for(ri i=0;i<coe[x].size();++i)update(abs(coe[x][i]));
}
inline int gcd(int a,int b){int t;while(b){t=a,a=b,b=t-t/a*a;}return a;}
void dfs(int p,int fa,int g,int coef){
	g=gcd(g,a[p]),ans+=coef*ask(g),change(g),siz[p]=1;
	for(ri i=0,v;i<e[p].size();++i){
		if(vis[v=e[p][i]]||v==fa)continue;
		dfs(v,p,g,coef),siz[p]+=siz[v];
	}
}
inline void solve(int p){
	vis[p]=1;
	++tim;
	change(a[p]);
	for(ri i=0,v;i<e[p].size();++i)if(!vis[v=e[p][i]])dfs(v,p,a[p],1);
	for(ri i=0,v;i<e[p].size();++i){
		if(vis[v=e[p][i]])continue;
		++tim,dfs(v,p,a[p],-1),mx=all=siz[v],getroot(v,p),solve(rt);
	}
}
int main(){
	n=read();
	for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
	for(ri i=1;i<=n;++i)a[i]=read(),lim=max(lim,a[i]);
	init();
	rt=0,mx=all=n,getroot(1,0),solve(rt);
	cout<<(ll)n*(n-1)/2-ans;
	return 0;
}
[NOIP2003]侦探推理题目通常涉及计算机科学中的算法和逻辑思维,尤其是搜索策略和数据结构。这类比赛的问题往往围绕着解决谜题、查找线索或模拟侦探调查的过程。例如,你可能会遇到类似“寻找隐藏的信息”、“排列与组合”或者“路径寻找”的场景。 举个例子,可能是关于迷宫寻路问题,你需要编写程序模拟侦探从起点到终点的最优路径,或者在一个虚拟的城市环境中找出特定嫌疑人的位置。Python作为简洁易读的编程语言,非常适合此类问题的解决方案,因为它有强大的列表操作和动态规划库如`heapq`(优先队列)或`networkx`(图论工具)。 在Python中实现侦探推理,一般会涉及以下几个步骤: 1. **理解输入**:解析给定的数据结构,比如二维数组表示的地图信息,字符串表示的人物关系等。 2. **构建模型**:如果问题是寻找最短路径,可以使用深度优先搜索(DFS)、广度优先搜索(BFS)或Dijkstra算法;如果是复杂的逻辑谜题,可能需要设计状态转移函数。 3. **编码实现**:利用Python的迭代或递归,以及数据结构特性来解决问题。 4. **验证结果**:检查找到的解是否满足题目条件,比如时间限制、路径长度等。 下面是一个简单的迷宫遍历的Python示例: ```python from collections import deque def explore(maze, visited, x, y): if x < 0 or y < 0 or x >= len(maze) or y >= len(maze[0]) or maze[x][y] == 'X': return False if maze[x][y] == 'S': return True visited.add((x, y)) if explore(maze, visited, x + 1, y): return True if explore(maze, visited, x - 1, y): return True if explore(maze, visited, x, y + 1): return True if explore(maze, visited, x, y - 1): return True visited.remove((x, y)) # 没有通路,回溯 return False maze = [...] visited = set() if explore(maze, visited, 0, 0): print("找到了出口") else: print("无法到达出口") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值