描述
给定一张N个点的有向图,点i到点j有一条长度为 i/(gcd(i,j))的边。有Q个询问,每个询问包含两个数x和y,求x到y的最短距离。
输入格式
第一行包含两个用空格隔开的整数,N和Q。
接下来Q行,每行两个数x和y。
输出格式
输出Q行整数,表示从x到y的最短距离。
样例输入
6 2 4 6 2 5
样例输出
2 2
数据范围与约定
- 对于30%的数据,1<=N<=100。
- 对于70%的数据,1<=N<=10^5。
- 对于100%的数据,1<=N<=10^7,1<=x,y<=N,Q<=10^5。
题解:
忽然发现,求1-n的质因数分解的和是可以线性筛的,怒赞!
为何不卡我们这些q*sqrt(n)的?出题人良心,好评!!!
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 10000000+1000 26 27 #define maxm 500+100 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define mod 1000000007 44 45 using namespace std; 46 47 inline int read() 48 49 { 50 51 int x=0,f=1;char ch=getchar(); 52 53 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 54 55 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 56 57 return x*f; 58 59 } 60 int n,m,tot,p[maxn],f[maxn]; 61 bool check[maxn]; 62 inline int gcd(int x,int y){return y?gcd(y,x%y):x;} 63 void get() 64 { 65 f[1]=1;tot=0; 66 for2(i,2,n) 67 { 68 if(!check[i]){p[++tot]=i;f[i]=i;}; 69 for1(j,tot) 70 { 71 int k=p[j]*i; 72 if(k>n)break; 73 check[k]=1; 74 f[k]=f[i]+p[j]; 75 if(i%p[j]==0)break; 76 } 77 } 78 } 79 80 int main() 81 82 { 83 84 freopen("input.txt","r",stdin); 85 86 freopen("output.txt","w",stdout); 87 88 n=read();m=read();get(); 89 while(m--) 90 { 91 int x=read(),y=read(); 92 if(x==y){printf("0 ");continue;}; 93 printf("%d ",f[x/gcd(x,y)]); 94 } 95 96 return 0; 97 98 }
补一下为什么质因数分解就是ans
假设求x->y的最短路,则直接走 这条路 长度为x/gcd(x,y)设这个长度的质因数分解为a1*a2*a3*a4……(两项可以相等)
然后要用到一个结论:
若a>=2,b>=2,则a+b<=a*b
移项就是 (1-a)*(1-b)>=1 这是显然的。
所以我们不妨把这个长度分开来走,
因为每拆一项都会使答案减小或不边,那我们不妨直接将该数全部分解为质数,一个一个质数来走。
举个例子
100-1,则100/gcd(100,1)的质因数分解为2*2*5*5
我们不妨使每次走的长度为2 2 5 5,而2+2+5+5=14<100 这样使长度之和达到最小。
所以我们可以这样走 100->50->25->5->1->1
有没有更短的路径呢?严格证法还待yy,不过貌似直觉上是显然的?