• [思维]Shortest Path in GCD Graph 2022杭电多校第9场 1008


    Problem Description

    There is an edge-weighted complete graph KnKn​ with nn vertices, where vertices are labeled through 1,2,...,n1,2,...,n. For each 1≤i

    You need to answer qq queries. In each query, given two vertices u,vu,v, you need to answer the length of the shortest path as well as the number of shortest paths between u,vu,v. Since the number of shortest paths may be too large, you only need to output it modulo 998244353998244353.

    Input

    The first line contains two integers n,q(2≤n≤107,1≤q≤50000)n,q(2≤n≤107,1≤q≤50000), denoting the number vertices in the graph and the number of queries, respectively.

    Then qq lines follow, where each line contains two integers u,v(1≤u,v≤n,u≠v)u,v(1≤u,v≤n,u=v), denoting a query between uu and vv.

    Output

    For each query, output one line contains two integers, denote the length and number of shortest path between given nodes, respectively. Note that only the number of shortest paths should be taken modulo 998244353998244353.

    Sample Input

    6 2

    4 5

    3 6

    Sample Output

    1 1

    2 2

    题意: 有一个由n个点构成的完全图,两点i,j之间的边权为gcd(i, j),有q次询问,每次询问给出u,v,求u到v的最短路长度和条数。

    分析: 当u和v互质时它们之间最短路一定是1,也就是直接从u走到v,条数也一定是1,当u和v不互指时最短路一定是2,因为可以从u先走到1,再从1走到v,而条数就是和u互质且和v互质的数字个数,不过当u和v的gcd本来就是2时还会多一条直接走过去的路,所以问题就转化为求n以内的和u*v互质的数字个数。先对u和v进行质因数分解,将它们出现过的质因数存下来,然后利用容斥定理可以求出与它俩不互质的数字个数,用n一减就是互质数字个数,不过这道题目时间限制比较紧,对于代码中的各种细节一定要注意优化,比如先筛出质数然后再质因数分解,容斥的时候利用lowbit快速定位1出现的位置,vector进行预分配内存等等。

    具体代码如下:

    1. #include
    2. using namespace std;
    3. const int mod = 998244353;
    4. int is_prime[10000005], prime[5000000], cnt, n, q, Log[10000005];
    5. int lowbit(int x){
    6. return x&-x;
    7. }
    8. void pre()
    9. {
    10. for(int i = 2; i <= n; i++)
    11. is_prime[i] = -1;
    12. for(int i = 0; i <= 20; i++)
    13. Log[1<
    14. for(int i = 2; i <= n; i++){
    15. if(is_prime[i])
    16. prime[++cnt] = i;
    17. for(int j = 1; j <= cnt && i*prime[j] <= n; j++){
    18. is_prime[i*prime[j]] = 0;
    19. if(i%prime[j] == 0)
    20. break;
    21. }
    22. }
    23. }
    24. signed main(){
    25. cin >> n >> q;
    26. pre();
    27. for(int i = 1; i <= q; i++){
    28. int u, v;
    29. scanf("%d%d", &u, &v);
    30. if(__gcd(u, v) == 1) puts("1 1");
    31. else{
    32. vector<int> p;
    33. p.reserve(20);
    34. unordered_map<int, bool> mp;
    35. int temp = u;
    36. for(int j = 1; prime[j]*prime[j] <= temp; j++){
    37. if(temp%prime[j] == 0){
    38. p.emplace_back(prime[j]);
    39. mp[prime[j]] = true;
    40. while(temp%prime[j] == 0)
    41. temp /= prime[j];
    42. }
    43. }
    44. if(temp != 1){
    45. p.emplace_back(temp);
    46. mp[temp] = true;
    47. }
    48. temp = v;
    49. for(int j = 1; prime[j]*prime[j] <= temp; j++){
    50. if(temp%prime[j] == 0){
    51. if(!mp[prime[j]])
    52. p.emplace_back(prime[j]);
    53. while(temp%prime[j] == 0)
    54. temp /= prime[j];
    55. }
    56. }
    57. if(temp != 1)
    58. if(!mp[temp])
    59. p.emplace_back(temp);
    60. long long num = 0;
    61. for(int j = 1; j < 1<size(); j++){
    62. int neg = 1;
    63. long long muti = 1;
    64. int temp = j;
    65. while(temp){
    66. neg ^= 1;
    67. int lb = lowbit(temp);
    68. muti *= p[Log[lb]];
    69. temp ^= lb;
    70. if(muti > n) break;
    71. }
    72. if(neg) num -= n/muti;
    73. else num += n/muti;
    74. }
    75. int ans = n-num;
    76. if(__gcd(u, v) == 2) ans++;
    77. printf("2 %d\n", ans);
    78. }
    79. }
    80. return 0;
    81. }

  • 相关阅读:
    Nacos 2.0 集群使用 Nginx 做代理
    链接生成-链接生成器-免费批量在线链接生成器
    [ Linux ] 进程控制 (1) 进程创建与进程终止
    [ 隧道技术 ] 反弹shell的集中常见方式(一)nc反弹shell
    【人民币识别】人民币序列号识别【含GUI Matlab源码 908期】
    vm+centos7安装
    Node-Web模块的用法
    Vue--router和route的区别
    ArrayList常见面试题
    Flink Yarn Per Job - CliFrontend
  • 原文地址:https://blog.csdn.net/m0_55982600/article/details/126373863