zoukankan      html  css  js  c++  java
  • bzoj3114 LCM Pair Sum

    题意:以质因数分解的方式给定n,求所有满足:lcm(a, b) = n的无序数对的价值和。其中(a, b)的价值为a + b

    解:

    定义首项为a,公比为q,项数为n的等比数列的和为getQ(a, q, n)

    首先考虑只有一个质因数,例如4。

    有如下数对:(1, 4), (2, 4), (4, 4)

    可得答案为getQ(1, 2, 2) + 43

    然后扩展:6。

    对于每个质因数来说:

    2: (1, 2), (2, 2)

    3: (1, 3), (3, 3)

    两两乘起来之后发现:少了一项(2, 3),这是由于我们用的是无序数对。那么改成有序数对试试。

     2:        3:

    (1, 2)    (1, 3)

    (2, 1)    (3, 1)

    (2, 2)    (3, 3)

    交叉相乘:

    (1, 6) (3, 2) (3, 6)

    (2, 3) (6, 1) (6, 3)

    (2, 6) (6, 2) (6, 6)

    发现所有无序数对除了(6, 6)之外都出现了两次,于是补上一个(6, 6)之后/2即可。

    现在考虑如何求交叉相乘的表。

    设我们的两列数对如下:

    (a, b)    (e, f)

    (c, d)    (g, h)

    要求的式子:

    ae + bf + ag + bh + ce + df + cg + dh

    因式分解:

    (a + c)(e + g) + (b + d)(f + h)

    考虑我们一开始列出来的某一列:

    2:

    (1, 2)

    (2, 1)

    (2, 2)

    可得:a + c = b + d

    故上式 = 2(a + c)(e + g)

    推广:

    设n = Πaipi,则ans = 2Π{getQ(1, a[i], p[i] + 1) + pi * aipi}

    复杂度TmlogV,其中V为指数值域。

     1 #include <cstdio>
     2 
     3 typedef long long LL;
     4 const int N = 17;
     5 const LL MO = 1e9 + 7;
     6 
     7 int a[N], p[N];
     8 
     9 inline LL qpow(LL a, LL b) {
    10     LL ans = 1;
    11     while(b) {
    12         if(b & 1) {
    13             ans = ans * a % MO;
    14         }
    15         a = a * a % MO;
    16         b = b >> 1;
    17     }
    18     return ans;
    19 }
    20 
    21 inline LL getQ(LL a, LL q, LL n) {
    22     a %= MO;
    23     if(!n) {
    24         return 0ll;
    25     }
    26     if(n == 1 || !a || !q) {
    27         return a;
    28     }
    29     if(n == 2) {
    30         return (a + a * q % MO) % MO;
    31     }
    32     if(n & 1) {
    33         return (a + getQ(a * q % MO, q, n - 1)) % MO;
    34     }
    35     return (qpow(q, n >> 1) + 1) * getQ(a, q, n >> 1) % MO;
    36 }
    37 
    38 inline void solve() {
    39     int n;
    40     scanf("%d", &n);
    41     for(int i = 1; i <= n; i++) {
    42         scanf("%d%d", &a[i], &p[i]);
    43     }
    44     LL ans = 2, sum = 1;
    45     for(int i = 1; i <= n; i++) {
    46         LL temp = qpow(a[i], p[i]) * p[i] % MO;
    47         (temp += getQ(1, a[i], p[i] + 1)) %= MO;
    48         ans = ans * temp % MO;
    49         (sum *= qpow(a[i], p[i])) %= MO;
    50         //printf("temp : %lld 
    ", temp);
    51     }
    52     //printf("sum = %lld 
    ", sum);
    53     ans = (ans + sum + sum) % MO;
    54     ans = ans * ((MO + 1) >> 1) % MO;
    55     printf("%lld
    ", ans);
    56     return;
    57 }
    58 
    59 int main() {
    60 
    61     int T;
    62     scanf("%d", &T);
    63     for(int i = 1; i <= T; i++) {
    64         printf("Case %d: ", i);
    65         solve();
    66     }
    67 
    68     return 0;
    69 }
    AC代码

    题外话:这东西是我在某个最小割练习题表里面看到的......

  • 相关阅读:
    来谈谈JAVA面向对象
    手把手的SpringBoot教程,SpringBoot创建web项目(一)
    【Java框架型项目从入门到装逼】第十五节
    印章文字识别
    《图像处理实例》之 曲线之间距离求解
    机器学习常用模块
    Ubutu16.04+Cuda9.2/9.0+Cudnn7.12/7.05+TensorFlow-gpu-1.8/1.6
    滑动平均模型原理+源码分析
    AlexNet实践
    TensorFlow NormLization
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10110751.html
Copyright © 2011-2022 走看看