• [思维]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. }

  • 相关阅读:
    数据分析---pandas模块
    SpringBoot+Mybaits搭建通用管理系统实例十一:数据缓存功能实现
    学 SQL 必须了解的 10 个高级概念!
    Blazor 使用拖放(drag and drop)上传文件 , 粘贴文件上传
    Git版本控制管理——补丁
    stm32-定时器输入捕获
    「UG/NX」Block UI 选择节点SelectNode
    FastApi项目搭建
    仅从个人的角度,聊聊年底的程序员招聘与入职情况
    java计算机毕业设计火车订票管理系统(附源码、数据库)
  • 原文地址:https://blog.csdn.net/m0_55982600/article/details/126373863