• hdu 5514Frogs


    gcd+容斥

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 1e4 + 10;
     5 ll n,m;
     6 int fac[maxn];
     7 int vis[maxn];
     8 int num[maxn];
     9  
    10 int main()
    11 {
    12     int T;
    13     scanf("%d",&T);
    14     for(int ii = 1; ii <= T; ii ++)
    15     {
    16         memset(vis,0,sizeof(vis));
    17         memset(num,0,sizeof(num));
    18         scanf("%I64d%I64d",&n,&m);
    19         int tot = 0;
    20         for(int i = 1; i * i <= m;i ++)
    21         {
    22             //找到所有m的因子 
    23             if(m % i == 0)
    24             {
    25                 fac[tot ++] = i;
    26                 if(i * i != m)
    27                 fac[tot ++] = m/i;
    28             }
    29         }
    30         //对因子排序 
    31         sort(fac,fac + tot);
    32         tot --;
    33         for(int i = 1; i <= n;i ++)
    34         {
    35             ll x;
    36             scanf("%I64d",&x);
    37             //每只青蛙能跳的石头是石头数与每只青蛙跳的距离的最大公约数的倍数,先找到d最大公约数 
    38             ll d = __gcd(x,m);
    39             //找到所有m因子中该青蛙能跳到的,记录为1 
    40             for(int j = 0; j < tot; j ++)
    41                 if(fac[j] % d == 0)
    42                     vis[j] = 1;
    43         }
    44         ll ans = 0;
    45         for(int i = 0; i < tot; i ++)
    46         {
    47             if(vis[i] != num[i])
    48             {
    49                 ll t = (m - 1)/fac[i];//此处m-1理解为虽然石头是m个,但是石头是从0开始标号的,所以减一。则t可以算出来这个因数在m-1范围内的最大倍数 
    50                 ans += t * (t + 1) / 2 * fac[i] * (vis[i] - num[i]);//等差数列前n项和*要乘的次数 
    51                 //对于t * (t + 1) / 2 * fac[i]这个公式,等差数列前n项和是一个变形,用的是n(a1+an)/2,an=n*a1,变形得到的 
    52                 for(int j = i + 1; j < tot; j ++)//再一次循环,因为前一步加的时候,所有最大公约数的倍数已经加上,所以后面万一重复要减去 
    53                 {
    54                     if(fac[j] % fac[i] == 0)//发现是之前最大公约数的倍数 
    55                     num[j] += vis[i] - num[i];//次数要改变(通过这个公式算正负零,后面统一加上就是答案) 
    56                 }
    57             }
    58         }
    59         printf("Case #%d: %I64d
    ",ii,ans);
    60     }
    61     return 0;
    62 }
  • 相关阅读:
    无重复字符的最长子串
    最长公共前缀
    项目开发的 工程化
    包管理 import debug 模块管理 module
    Third Party Browser Drivers NOT DEVELOPED by seleniumhq
    任何不看源码的代码引入都是存在定时爆炸的可能
    博客数计数
    lineage 世系 血缘 容错机制 DAG
    查源码分析 游标 写 需要 cursors 一切不看源码的代码引入都是定时炸弹的启动
    8核 16g 及时释放内存空间
  • 原文地址:https://www.cnblogs.com/lyqf/p/9801056.html
Copyright © 2020-2023  润新知