题面:https://www.cnblogs.com/Juve/articles/11639923.html

simple:

考试时只想到的暴力exgcd判断

考虑n,m互质的情况:

我们枚举y,对于方程$n*x+m*y \leq q$,$x\leq\frac{q-m*y}{n}$

其中y的范围是[0,n-1],因为如果y大于n-1,那么可以使x的系数加一,会有重复

然后如果n,m不互质,那么设$n=n'*gcd(n,m),m=m'*gcd(n,m)$,所以$n'*gcd(n,m)*x+m'*gcd(n,m)*y \leq q$

其中把$gcd(n,m)*y$看成一个整体,那么枚举y的范围要保证$gcd(n,m)*y\in[0,n-1]$

然后就A了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 using namespace std;
 7 const int MAXN=1e5+5;
 8 int t,n,m,q,ans;
 9 int gcd(int a,int b){
10     return b==0?a:gcd(b,a%b);
11 }
12 int max(int a,int b){return a>b?a:b;}
13 signed main(){
14     scanf("%lld",&t);
15     while(t--){
16         scanf("%lld%lld%lld",&n,&m,&q);
17         int g=gcd(n,m);
18         ans=0;
19         for(int i=0;i<(n/g);++i){
20             int x=q-i*m;
21             if(x<0) break;
22             ans+=x/n+1;
23         }
24         printf("%lld\n",q-(ans-1));
25     }
26     return 0;
27 }
View Code

walk:

枚举gcd,然后把边权是gcd倍数的边建出来,形成一个森林,求出森林的直径即是答案为gcd时的边的长度

注意一点,有些长度可能不会出现在最长链中,因为他是构成最长链的一部分,所以如果这个长度的答案<长度大于他的答案的话,就要将长度大于他的答案给他,从大到小枚举ans[i]=max(ans[i],ans[i+1]).

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=4e5+5;
const int MAXM=1e6+5;
int n,maxx=0,res[MAXN],len=0;
vector< pair<int,int> >e[MAXM];
int to[MAXN<<1],nxt[MAXN<<1],pre[MAXN],cnt=0;
void add(int u,int v){
	++cnt,to[cnt]=v,nxt[cnt]=pre[u],pre[u]=cnt;
}
bool vis[MAXN];
int sta[MAXM],top=0;
int dfs(int x,int fa){
	vis[x]=1;
	int l=0,r=0;
	for(int i=pre[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa||vis[y]) continue;
		int p=dfs(y,x);
		if(p+1>l) r=l,l=p+1;
		else if(p+1>r) r=p+1;
	}
	len=max(len,l+r);
	return l;
}
int main(){
	scanf("%d",&n);
	for(int i=1,u,v,w;i<n;++i){
		scanf("%d%d%d",&u,&v,&w);
		maxx=max(maxx,w);
		e[w].push_back(make_pair(u,v));
	}
	for(int i=1;i<=maxx;++i){
		cnt=0;
		for(int j=i;j<=maxx;j+=i){
			int N=e[j].size();
			for(int k=0;k<N;++k){
				int u=e[j][k].first,v=e[j][k].second;
				add(u,v),add(v,u);
				sta[++top]=u,sta[++top]=v;
			}
		}
		for(int j=1;j<=top;++j){
			if(!vis[sta[j]]){
				len=0;
				dfs(sta[j],0);
				res[len]=max(res[len],i);
			}
		}
		for(int j=1;j<=top;++j){
			pre[sta[j]]=vis[sta[j]]=0;
		}
		top=0;
	}
	for(int i=n-1;i>=1;--i) res[i]=max(res[i],res[i+1]);
	for(int i=1;i<=n;++i) printf("%d\n",res[i]);
	return 0;
}
01-14 22:37
查看更多