首页 > 技术文章 > 题解-CF360D Levko and Sets

George1123 2020-12-28 16:42 原文

题面

CF360D Levko and Sets

给定 \(a\{n\}\)\(b\{m\}\) 和质数 \(p\)。对于每个 \(a_i\),生成一个集合,刚开始只有 \(1\),每次从集合中选一个元素 \(c\),对于所有的 \(j\),如果满足 \(c\times a_i^{b_j}\bmod p\) 不在当前集合,就把它加入集合。求 \(n\) 个集合并的大小。

数据范围:\(1\le n\le 10^4\)\(1\le m\le 10^5\)\(2\le p\le 10^9\)


题解

之前 VP 场上没做出来后来学了 zhouyuyang 的做法,然后发现学了个假做法。

Hack2 1 13 3 5 1;答案:6;错误输出:7

\(\varphi=p-1\)\(g=\gcd(\varphi,\gcd_{i=1}^m b_i)\)\(G\)\(p\) 任意一个原根。

很明显每个集合元素就是 \(\{a_i^{gk}\bmod p|k\in N\}\)

\(u^{x}\equiv u^{x\bmod \varphi}\pmod p\)\(x\in[0,\varphi)\)\(f(x)=G^{x}\in [1,p)\) 一一对应。

所以搞出所有 \(\varphi\) 的因数,可以得到对于所有的 \(i\),最小的 \(c_i\) 满足 \({a_i}^{gc_i}\equiv 1\pmod p\)。那么这个集合有 \(c_i\) 个元素。

考虑是哪 \(c_i\) 个元素:\(\{a^{g},a^{2g},...,a^{(c_i-1)g}\}\)\(\bmod p\),下同)。

或者说:\(\{G^{0},G^{\varphi/c_i},G^{2\varphi/c_i},...,G^{(c_i-1)\varphi/c_i}\}\)。这两个集合是等价的。

\(s_i=\frac{\varphi}{c_i}\),求 \(n\) 个集合的并集,问题转化为:有多少个 \(1\le x\le \varphi\) 满足 \(\exists s_i|x\)

很多人这里写错了,可是 Codeforces 的数据不强,误导了好多人。

\(d|\varphi:f(d)\) 表示 \(d\) 的倍数中只被 \(d\) 标记不被 \(d\) 的其他是 \(\varphi\) 的因数的倍数标记的数的个数。

如果 \(\exists s_i|d\)\(f(d)=\frac{\varphi}{d}-\sum_{dk|\varphi}f(dk)\);否则 \(f(d)=0\)

然后答案是 \(\sum_{d|\varphi} f(d)\),时间复杂度 \(\Theta((n+m)\log p+d(\varphi)(n+d(\varphi)))\)


代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define x first
#define y second
#define bg begin()
#define ed end()
#define pb push_back
#define mp make_pair
#define sz(a) int((a).size())
#define R(i,n) for(int i(0);i<(n);++i)
#define L(i,n) for(int i((n)-1);i>=0;--i)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f;

//Data
const int N=1e4,M=1e5,d_N=4e4;
int n,m,p,a[N],b[M],c[N];
int d_n,pd[d_N],f[d_N];

//Math
int gcd(int a,int b){return a?gcd(b%a,a):b;}
int mypow(int a,int x=p-2,int res=1){
    for(;x;x>>=1,a=1ll*a*a%p)
        (x&1)&&(res=1ll*res*a%p);
    return res;
}

//Main
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m>>p;
    int phi=p-1,g=phi;
    R(i,n) cin>>a[i];
    R(i,m) cin>>b[i],g=gcd(g,b[i]);
    for(int d=1;d*d<=phi;++d)if(phi%d==0)
        pd[d_n++]=d,d*d<phi?pd[d_n++]=phi/d:0;
    sort(pd,pd+d_n);
    R(i,n){
        int t=mypow(a[i],g);
        R(j,d_n)if(mypow(t,pd[j])==1)
            {c[i]=phi/pd[j]; break;}
    }
    int ns=0;
    L(i,d_n){
        bool mark=false;
        R(j,n)if(pd[i]%c[j]==0){mark=true; break;}
        if(mark){
            f[i]=phi/pd[i];
            for(int j=i+1;j<d_n;++j)
                if(pd[j]%pd[i]==0) f[i]-=f[j];
            ns+=f[i];
        }
    }
    cout<<ns<<'\n';
    return 0;
}

祝大家学习愉快!

推荐阅读