zoukankan      html  css  js  c++  java
  • Steins;Gate

    传送门

    给出一个序列(a),对于每一个(a_k),输出有多少个有序二元组(a_i imes a_jequiv (mod a_k))

    这看一眼就像是fft问题,fft一般可以统计加法的情况,但这里是乘法。

    原根可以把乘法变成加法,仔细一看模,是([2,200000])的质数,根据原根存在定理,奇质数肯定存在原根,2也存在原根。

    求质数的原根,时间复杂度是(O(plogp))

    然后利用原根打一个指标表,是(O(n))

    然后再利用原根把所有的非零(a_i)转换为指标,把序列(a)的各项的指标作为系数累积。

    最后把这个多项式进行自乘。

    就能得到一个指标多项式。

    原根可以把乘法变成加法,然后利用fft的性质求解

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    template<typename T = long long> inline T read() {
        T s = 0, f = 1; char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
        return s * f;
    }
    const int N = 5e5 + 5;
    namespace PrimitiveRoot {
        vector<int> PrimeFactor(int n) {//分解质因子
            vector<int> fac;
            for(int i = 2; i * i <= n; ++i) {
                if(n % i == 0){
                    fac.push_back(i);
                    while(n % i == 0) n /= i;
                }
            }
            if(n > 1) fac.push_back(n);
            return fac;
        }
        int gcd(int a, int b){
            return b == 0 ? a : gcd(b, a % b);
        }
        ll qpow(ll a, ll b, ll p){
            ll ans = 1; a %= p;
            while(b){
                if(b & 1) ans = ans * a % p;
                a = a * a % p;
                b >>= 1;
            }
            return ans;
        }
        int phi(int n){
            return n - 1;
            int ans = n;
            for(int i = 2; i * i <= n; i++){
                if(n % i == 0){
                    ans -= ans/i;
                    while(n % i == 0) n /= i;
                }
            }
            if(n > 1) ans -= ans / n;
            return ans;
        }
        bool checkroot(int x) {
            if(x == 2 ||x == 4) return true;
            if(x % 4 == 0) return false;
            if(x % 2 == 0) x /= 2; 
            for(int i = 2; i * i <= x; ++i){
                if(x % i == 0){
                    while(x % i == 0) x /= i;
                    return x == 1;
                }
            }
            return true;
        }
        int PrimitiveRoot(int p) { // 求p最小的原根
            int nowphi = phi(p);
            std::vector<int> fac = PrimeFactor(nowphi);
            for(int g = 2; g < p; g++) {
                bool f = 1;
                for(int j = 0; j < fac.size(); j++)
                    if(qpow(g, nowphi / fac[j], p) == 1) {f = 0; break; }
                if(f) return g;
            }
            return -1; // 没有原根
        }
        void solve(int x){ //得到全部的原根
            if(!checkroot(x)) {
                printf("0
    ");; return;
            }
            int nowphi = phi(x);
            int g = PrimitiveRoot(x);
            vector<int> ans; ans.push_back(g); // 所有原根
            for(int i = 2; i < nowphi; ++i){
                if(gcd(i, nowphi) == 1) ans.push_back(qpow(g, i, x));
            }
        }
    };
    struct Complex{
        double x, y;
        Complex(double x = 0, double y = 0):x(x),y(y){};
        inline Complex operator + (const Complex b) const {
            return Complex(x + b.x,y + b.y);
        }
        inline Complex operator - (const Complex b) const {
            return Complex(x - b.x,y - b.y);
        }
        inline Complex operator * (const Complex b) const {
            return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
        }
    };
    namespace FFT{
        const double Pi = acos(-1);
        const int N = 5e5 + 5; // 刚好比n大的2的k次方再乘2
        Complex F[N], G[N];
        int r[N], n, m;
        void FFT(Complex *a, int n, int inv){
            for(int i = 0; i < n; i++)
                if(r[i] > i) swap(a[r[i]], a[i]);
     
           for(int mid = 2; mid <= n; mid <<= 1){
                Complex x(cos(2 * Pi / mid), inv * sin(2 * Pi / mid));
                for(int i = 0; i < n; i += mid){
                    Complex w(1,0);
                    for(int j = i; j < i + (mid >> 1); j++, w = w * x){
                        Complex t1 = a[j],t2 = a[j + (mid >> 1)] * w;
                        a[j] = t1 + t2; a[j + (mid >> 1)] = t1 - t2;
                    }
                }
            }
        }
        void mul(ll *a, ll *b, ll *c, int nn, int mm, int &k) {
            n = nn, m = mm;
            for(mm += nn, nn = 1; nn <= mm; nn *= 2);
            for(int i = 0; i <= nn; i++) F[i].x = F[i].y = G[i].x = G[i].y = 0;
            for(int i = 0; i <= n; i++) F[i].x = a[i];
            for(int i = 0; i <= m; i++) G[i].x = b[i];
            int l = 0;
            for(m += n, n = 1; n <= m; n *= 2, l++);
            for(int i = 0; i < n; i++)
                r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
            FFT(F, n, 1); FFT(G, n, 1);
            for(int i = 0; i < n; i++) F[i] = F[i] * G[i];
            FFT(F, n, -1);  k = m;
            for(int i = 0; i <= m; i++) {
                c[i] = (ll)(F[i].x / n + 0.5);
            }
        }
    };
    int I[N];
    void I_table(int g, int p){
        int base = 1;
        for(int i = 1; i < p - 1; i++) {
            base = base * g % p;
            I[base] = i;
        }
    }
    int a[N], b[N];
    ll xishu[N], ans[N], c[N];
    int main() {
        int n = read(), p = read();
        I_table(PrimitiveRoot::PrimitiveRoot(p), p);
        for(int i = 1; i <= n; i++) a[i] = read();
        int tot = 0;
        for(int i = 1; i <= n; i++) {
            if(a[i] % p == 0) tot++;
            else xishu[I[a[i] % p]]++;
        }
        int m;
        FFT::mul(xishu, xishu, c, p - 1, p - 1, m);
    
        for(int i = 0; i < p * 2; i++) ans[i % (p - 1)] += c[i];
        for(int i = 1; i <= n; i++) {
            if(a[i] >= p) printf("0
    ");
            else if(a[i] == 0) printf("%lld
    ", 1ll * tot * (n - tot) * 2 + 1ll * tot * tot);
            else printf("%lld
    ", ans[I[a[i]]]);
        }
        return 0;
    }
    
    I‘m Stein, welcome to my blog
  • 相关阅读:
    基于Python实现的死链接自动化检测工具
    MySQL 慢查询日志配置与简析
    Git 常用命令及操作总结
    redis redis常用命令及内存分析总结(附RedisClient工具简介
    Jenkins Jenkins结合GIT Maven持续集成环境配置
    JAVA TestNG单元测试详解
    MyEclipse TestNG插件安装与配置
    JAVA 利用MyEclipse结合TestNG测试框架进行单元测试
    lintcode :前序遍历和中序遍历树构造二叉树
    lintcode: 中序遍历和后序遍历树构造二叉树
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14392274.html
Copyright © 2011-2022 走看看