• 洛谷 P3307: bzoj 3202: [SDOI2013] 项链


    题目传送门:洛谷P3307。这题在bzoj上是权限题。

    题意简述:

    这题分为两个部分:

    ① 有一些珠子,每个珠子可以看成一个无序三元组。三元组要满足三个数都在$1$到$m$之间,并且三个数互质,两个珠子不同当且仅当这个三元组不同。计算有多少种不同的珠子。

    ② 把这些珠子串成一个环,要满足相邻的珠子不同。两个环不同当且仅当旋转任意角度后仍然不同。计算有多少种不同的环。

    题解:

    分成两部分做。

    第一部分:

    考虑计算三元组的个数,转无序为有序,再去重。

    答案=(三个都不同的有序三元组方案)/6+(两个相同,另一个不同的方案)/3+(三个都相同的方案)。

    容斥一下得到答案=(三元组的方案+二元组的方案*3+一元组的方案*2)/6。

    因为一元组只有(1)满足条件,所以答案是(2+三元组的方案+二元组的方案*3)/6。

    考虑如何求出两种方案。

    三元组的方案是(sum_{i=1}^msum_{j=1}^msum_{k=1}^m[gcd(i,j,k)=1]),二元组同理。

    显然是莫反套路,三元组的答案是(sum_{d=1}^mmu(d){leftlfloorfrac{m}{d} ight floor}^3),二元组同理。

    数论分块求出答案即可,最后乘上6的逆元。这一步复杂度$Theta(m+Tsqrt{m})$。

    第二部分:

    知道了不同珠子的数量,要求出本质不同的环的个数。

    Burnside引理套路。最终方案数等于每个置换的不动点个数的平均数,即(frac{1}{n}sum_{i=1}^nf(i)),(f(i))表示旋转(i)格的不动点数量。

    稍微化简一下:(frac{1}{n}sum_{d|n}varphi(frac{n}{d})f(d))。

    考虑计算(f(x)),当$x$是$n$的因数时,$f(x)$就等于不考虑旋转时的长度为$x$的环的数量。

    假设不同珠子的数量为(k),不加证明地给出一个式子:(f(x)=(k-1)^x+(-1)^x(k-1))。这个式子可以递推得出。

    那么根据这个式子和上面的式子计算即可。

    要注意(n)太大了,要求出(varphi)的值比较困难,考虑DFS它的每个质因数,按照(varphi)是个积性函数以及公式,求得(varphi)。

    要注意,最后除掉(n)的时候,(n)可能是模数的倍数导致没有逆元。可以发现(n)不会是模数平方的倍数,所以把模数平方后再做一遍,最后除掉模数这个因子即可。

      1 #include <cstdio>
      2 
      3 #define reg register
      4 typedef unsigned long long ULL;
      5 const ULL MOD = 1000000007ll;
      6 const ULL Inv61 = 166666668ll;
      7 const ULL Inv62 = 833333345000000041ll;
      8 ULL Mod;
      9 ULL Inv6;
     10 const int MN = 10000001;
     11 
     12 ULL TN[11];
     13 int TA[11], MA;
     14 
     15 bool ip[MN];
     16 int p[MN], pc;
     17 int mu[MN];
     18 inline void SieveInit() {
     19     ip[0] = ip[1] = 1;
     20     mu[1] = 1;
     21     for (reg int i = 2; i <= MA; ++i) {
     22         if (!ip[i])
     23             p[++pc] = i,
     24             mu[i] = -1;
     25         for (reg int j = 1; j <= pc; ++j) {
     26             reg int k = p[j] * i;
     27             if (k > MA) break;
     28             ip[k] = 1;
     29             if (i % p[j]) mu[k] = -mu[i];
     30             else break;
     31         }
     32     }
     33     for (reg int i = 2; i <= MA; ++i)
     34         mu[i] += mu[i - 1];
     35 }
     36 
     37 int O;
     38 inline ULL Mul(ULL x, ULL y) {
     39     if (!O) return x * y % Mod;
     40     return (x * y - (ULL)((long double) x / Mod * y) * Mod + Mod) % Mod;
     41 }
     42 
     43 ULL N; int A;
     44 ULL M;
     45 inline void SolveM() {
     46     M = 2;
     47     for (reg int i = 1, j, k; i <= A; i = j + 1) {
     48         k = A / i, j = A / k;
     49         M = (M + Mul(Mul(Mul(k, k), k + 3), (mu[j] - mu[i - 1] + Mod) % Mod)) % Mod;
     50     }
     51     M = Mul(M, Inv6);
     52 }
     53 
     54 ULL Pow[60];
     55 inline void PowInit() {
     56     Pow[0] = M - 1;
     57     for (reg int i = 1; i < 60; ++i) Pow[i] = Mul(Pow[i - 1], Pow[i - 1]);
     58 }
     59 inline ULL qPow(ULL E) {
     60     ULL A = 1;
     61     for (reg int j = 0; E; E >>= 1, ++j)
     62         if (E & 1) A = Mul(A, Pow[j]);
     63     return A;
     64 }
     65 inline ULL Inv(ULL B) {
     66     ULL A = 1;
     67     for (reg ULL E = MOD - 2; E; E >>= 1, B = B * B % MOD)
     68         if (E & 1) A = A * B % MOD;
     69     return A;
     70 }
     71 
     72 ULL b[15]; int e[15], cnt;
     73 ULL Ans;
     74 inline ULL F(ULL x) {
     75     return (qPow(x) + (x & 1 ? Mod - M + 1 : M - 1)) % Mod;
     76 }
     77 void DFS(int st, ULL now, ULL phi) {
     78     if (st > cnt) {
     79         Ans = (Ans + Mul(phi % Mod, F(N / now))) % Mod;
     80         return;
     81     }
     82     DFS(st + 1, now, phi);
     83     for (reg int i = 1; i <= e[st]; ++i) {
     84         now *= b[st];
     85         phi *= i == 1 ? b[st] - 1 : b[st];
     86         DFS(st + 1, now, phi);
     87     }
     88 }
     89 inline ULL Solve() {
     90     ULL NN = N; cnt = 0;
     91     for (reg ULL i = 2; i * i <= NN; ++i) if (NN % i == 0) {
     92         b[++cnt] = i, e[cnt] = 0;
     93         while (NN % i == 0) NN /= i, ++e[cnt];
     94     } if (NN > 1) b[++cnt] = NN, e[cnt] = 1;
     95     Ans = 0; DFS(1, 1, 1);
     96     if (O) Ans = Ans / MOD * Inv(N / MOD) % MOD;
     97     else Ans = Ans * Inv(N % MOD) % MOD;
     98     return Ans;
     99 }
    100 
    101 int main() {
    102     int Tests;
    103     scanf("%d", &Tests);
    104     for (int i = 1; i <= Tests; ++i)
    105         scanf("%llu%d", TN + i, TA + i),
    106         MA = TA[i] > MA ? TA[i] : MA;
    107     SieveInit();
    108     for (int i = 1; i <= Tests; ++i) {
    109         N = TN[i], A = TA[i];
    110         O = N % MOD ? 0 : 1;
    111         if (O) Mod = MOD * MOD, Inv6 = Inv62;
    112         else Mod = MOD, Inv6 = Inv61;
    113         SolveM();
    114         PowInit();
    115         printf("%llu
    ", Solve());
    116     }
    117     return 0;
    118 }
    119 
    120 // 1. 求出本质不同的珠子数量,容斥 + 莫比乌斯反演 + 数论分块
    121 // 2. 求出答案,Burnside 引理 + 数论分块
  • 相关阅读:
    改变windows下installer文件夹位置,目录链接(不是快捷方式)
    SQL2008根据日志恢复
    HTML5实践
    人类的本能——自私与善
    打油诗 看《大上海》
    POSA2:Wrapper Facade模式
    解析XML文件
    MediaWiki编辑工具
    每周一荐:设计模式
    每周一荐:分布式计算的模式语言
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/10166806.html
Copyright © 2020-2023  润新知