• 【Foreign】光 [莫比乌斯反演]


    Time Limit: 10 Sec  Memory Limit: 128 MB

    Description

      天猫有一个长方形盒子,长宽分别为A,B。
      这个长方形盒子的内壁全部是镜面。
      天猫在这个盒子的左下方放了一个激光灯。
      这个灯可以照向盒子内的任意角度。
      现在天猫想要打开这个激光灯,但是他想让光线按照如下规则照射:
        1.这束光必须恰好打到盒子边缘反射D次,并且不能碰到任意一个角落(除了出发点以及结束点)。
        2.这束光必须到达盒子右上角,并且结束反射。
      天猫想要知道,所有合法的光线路线的长度平方和是多少。
      作为一个资深OIer,你应该知道输出要对10^9+7取模。

    Input

      一行三个数,表示A、B、D。

    Output

      一个数,表示路径平方和。

    Sample Input

      3 3 2

    Sample Output

      180

    HINT

      D<=10^9, A,B<=10^6

    Solution

      首先,我们注意到若一束光在一个平面反射,相当于镜面一侧的物体对称到镜面另一侧,而光线穿过镜面照到物体成的虚像上。
      所以,我们可以认为:有一个D∗D的网格,需要在这个网格上面找到一点(x,y),要满足x+y−2 = D,这样的话,我们把(0,0)(x,y)连接起来,连线所经过的网格边就是镜面反射时经过的边。也就是说,任意的合法方案整数对(x,y)是一一对应的。
      注意,由于在反射过程中,不能碰到网格的角落,所以应该满足(0,0)(x,y)连线上没有其他整点,也就是gcd(x,y)=1,即gcd(x,D+2)=1

      然后用莫比乌斯反演推一波式子,最后发现要用暴力解决qaq。

      

    Code

     1 #include<iostream>    
     2 #include<string>    
     3 #include<algorithm>    
     4 #include<cstdio>    
     5 #include<cstring>    
     6 #include<cstdlib>
     7 #include<cmath>
     8 #include<bitset>
     9 using namespace std;  
    10 typedef long long s64;
    11 
    12 const int ONE = 50005;
    13 const int MOD = 1e9 + 7;
    14 const int Niyu = 166666668;
    15 
    16 s64 A, B, D;
    17 int P[ONE],num;
    18 int vis[ONE];
    19 s64 Ans;
    20 
    21 int get()
    22 {    
    23         int res=1,Q=1;char c;    
    24         while( (c=getchar())<48 || c>57 ) 
    25         if(c=='-')Q=-1; 
    26         res=c-48;     
    27         while( (c=getchar())>=48 && c<=57 )    
    28         res=res*10+c-48;    
    29         return res*Q;
    30 }
    31 
    32 void Factor(int x)
    33 {
    34         for(int i=2; i*i<=x; i++)
    35         if(x % i == 0)
    36         {
    37             P[++num] = i;
    38             while(x % i == 0) x /= i;
    39         }
    40         if(x != 1) P[++num] = x;
    41 }
    42 
    43 int Calc(int n)
    44 {
    45         return (s64)n * (n+1) % MOD * (2*n+1) % MOD * Niyu % MOD; 
    46 }
    47 
    48 void Deal()
    49 {
    50         int d = 1, N = 0;
    51         for(int i=1; i<=num; i++)
    52             if(vis[i]) d = (s64)d * P[i] % MOD ,N++;
    53         N = N & 1 ? MOD-1 : 1;
    54         Ans = Ans + (s64)N % MOD * d % MOD * d % MOD * Calc((D+2) / d) % MOD,
    55         Ans %= MOD; 
    56 }
    57 
    58 void Dfs(int T)
    59 {
    60         if(T > num) {Deal(); return;}
    61         vis[T] = 1; Dfs(T+1);
    62         vis[T] = 0; Dfs(T+1);
    63 }
    64 
    65 int main()
    66 {
    67         cin>>A>>B>>D;
    68         if(D & 1) {printf("0"); return 0;}
    69         Factor(D + 2);
    70         Dfs(1);
    71         printf("%d", (s64)(A * A % MOD + B * B % MOD) % MOD * Ans % MOD);
    72 } 
    View Code

  • 相关阅读:
    326周日去找书
    新视野大学英语-Book1
    预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)
    自定义GRUB主题
    Linux安装CMake
    Linux编译安装Apache
    @Scheduled注解
    熵权可拓物元模型
    Linux更新Python3.8
    Linux下更新GCC
  • 原文地址:https://www.cnblogs.com/BearChild/p/7071104.html
Copyright © 2020-2023  润新知