[十二省聯考2019]騙分過樣例

傳送門

  這道題是個毒瘤題,花費了我\(\text{1day}\)獨立解決\(16\)個子任務。下面步入正題。c++

subtask 1-3:1_998244353

  這個觀察數據不可貴出要求\(19^x\bmod 998244353\),直接搞便可。注意到可能\(x\)很是大,根據費馬小定理\(x^{P-1} \equiv 1 \pmod P\),咱們須要讀入取模git

subtask 4:1?

  觀察數據和提示告訴咱們:仍然求\(19^x\),只不過模數不知道。發現輸出文件的最大值在\(10^6\)左右,咱們拿第一個輸入直接爆搜檢驗,最後能找出來\(P=1145141\)算法

subtask 5:1?+

  這個是前一個的增強版,發現模數在\(5\times 10^{18}\)左右,這個很差暴力了。怎麼辦呢?我把輸入的數排了個序,發現有兩組輸入的\(x\)之差爲\(2\),因而我找到這兩組對應的輸出,獲得了:\(19^{264708066}\equiv 1996649514996338529 \pmod P\)\(19^{264708068}\equiv 1589589654696467295 \pmod P\)。也就是說上面的式子乘上\(19^2\)再取模就能獲得下面的數字,因而咱們獲得了:\(1996649514996338529\times 19^2 \equiv 1589589654696467295 \pmod P\)。而後改寫這個式子:\(1996649514996338529\times 361-nP=1589589654696467295\),把常數移到右邊,發如今\(long\ long\)範圍內沒法算出,我用\(long\ double\)算出了近似值。而後\(P\)必定是這個數的一個因子。發現\(n\)\(100\)\(200\)左右,我就暴力試除,考慮到精度又將\(\pm 1000\)的模數用第一組輸入輸出判斷了一下,最後找到了模數\(P=5211600617818708273\)函數

subtask 6-7:1wa_998244353

  發現並非求\(19^x \bmod 998244353\)了,換成了用\(int\)一步一步直接乘再取模,忽視溢出等問題。代碼以下。測試

x = (int)(x * 19) % 998244353;

  第\(6\)個點直接順序求解便可。第\(7\)個點恐怕不太行,\(x\)太大了。我一開始想改寫快速冪來求解,發現行不通。正當我束手無策的時候,我讓第\(6\)個點多跑到\(10^6\)組,發現了循環節。就是從\(x=55246\)開始,答案每過\(45699\)個數循環一次。這讓我想起了\(\text{Pollard-Rho}\)算法的\(\rho\)。固然與那個算法沒有關係,這裏直接用上述性質便可。ui

subtask 14-16:2g && 2g+

  當時我在作完前面\(6\)\(\text{subtask}\)後緊接着作的。前面兩個點,每次詢問給你三個數\(l\)\(r\)\(P\),要求\(l\)\(r\)在模\(P\)下的原根。對於第\(14\)個點,\(P=998244353\)時,\(\varphi(P)=P-1=998244352=2^{23}\times 7\times 17\),由於不一樣的質因子只有\(3\)個,因此能夠直接試除判斷是否爲原根。spa

  對於第\(15\)個點,\(P=13123111\)\(\varphi(P)=13123110=2×3×5×7×11×13×19×23\),並且判斷的數字多達\(10^7\)個,試除確定會\(\text{T}\)。咱們能夠利用其中一個原根把其餘的原根遍歷出來。在這裏\(g\)\(6\),由於\(g^t\)遍歷全部\(\varphi(P)\)個與\(P\)互質的數,而當且僅當\(t\)\(\varphi(P)\)互質的時候\(g^t\)也是原根。因而咱們用\(\varphi(P)\)的質因子對\(t\)進行取模判斷。遍歷完後原根就找全了。code

  對於第\(16\)個點,最後一組詢問未知模數,根據數據給的原根咱們反求模數。提示說在\(10^9\)\(2\times 10^9\)之間且是個質數,咱們一個一個找,而後藉助已有的原根經過試除法判斷這個質數可不可行。\(\forall g\),若是\(g^\frac{P-1}{2}\not\equiv 1 \pmod P\),則\(P\)極可能是咱們要找的模數。個人電腦跑了大約\(5min\)找到了一個數\(P=1515343657\),而後檢驗發現是正確的。用它搜原根與用\(P=998244353\)的方法同樣。因而就解決了。get

subtask 8-10:2p

  要求咱們判斷\(l\)\(r\)內每一個數是否是質數。小範圍的能夠用線性篩,範圍稍微大點的可能能夠篩一部分數而後用這部分數來篩\(l\)\(r\)。我直接上了\(\text{Miller-Rabin}\),這個算法能夠在\(\log n\)的時間內測試一個數是否是質數,正確率爲\(1-(\frac{1}{4})^s\)\(s\)爲測試次數。這題貌似選取兩三個數就能夠了,這樣常數小全能過。it

subtask 11-13:2u

  這裏讓咱們篩出\(l\)\(r\)的莫比烏斯函數。

  同上面同樣,咱們能夠小範圍地篩出來\(\mu\)過掉前兩個點。當時我沒有這麼想,用了\(\text{Pollard-Rho}\)來暴力分解而後篩出前\(10^6\)個莫比烏斯函數,發現第二個點都過不掉。怎麼辦呢?最大的數爲\(10^{18}\),我想到若是篩出\(10^6\)之內的質數而後用這些質數來篩這些數,剩下的數的素因子必定\(\geq 10^6\),因此剩下的數最多只能有兩個素因子,也就是如下三種狀況:

  1、剩下的數是質數,用\(\text{Miller-Rabin}\)判一下,這個時候會使\(\mu\)乘上\(-1\)

  2、剩下的數是兩個不一樣的質數的乘積;負負得正,這個時候不會對\(\mu\)產生貢獻;

  3、剩下的數是一個質數的平方。這個時候\(\mu\)\(0\)

  用小於\(10^6\)的因子去篩這些數,而且維護\(\mu\),而後經過上面的三種狀況分類討論便可求解。

  但要注意要去掉含有平方因子的數。最後這道題就解完了。

\\ AC代碼
#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define ull unsigned long long
#define rep(i, a, b) for (register int i = a, end = b; i <= end; i++)
#define repd(i, a, b) for (register int i = a, end = b; i >= end; i--)
#define chkmax(a, b) a = max(a, b)
#define chkmin(a, b) a = min(a, b)
#define INF (1<<30)
#define pb push_back
#define mp(a, b) make_pair(a, b)
#define fst first
#define snd second
#define pii pair<int, int>

char s[15];

namespace _998244353 {
    int N;
    ull P;
    ull v;

    inline void inc(ull &a, ull b, ull p) {
        a += b;
        if (a >= p) a -= p;
    }

    ull Mult(ull a, ull b, ull p) {
        ull res = 0;
        for (ull k = a; b; inc(k, k, p), b >>= 1)
            if (b & 1) inc(res, k, p);
        return res;
    }

    ull qpow(ull a, ull b, ull p) {
        ull res = 1;
        for (register ull k = a; b; k = Mult(k, k, p), b >>= 1)
        if (b & 1) res = Mult(res, k, p);
        return res;
    }

    inline ull read() {
        ull w = 0; char c;
        while (!isdigit(c = getchar())) ;
        while (isdigit(c)) w = ((w << 3) + (w << 1) + (c ^ 48)) % (P-1), c = getchar();
        return w;
    }
    void main(ull orz) {
        P = orz;
        scanf("%d", &N);
        rep(i, 1, N) {
            v = read();
            printf("%llu\n", qpow(19, v, P));
        }
    }
}

namespace WA {
    int N;
    int ans[55246+45699+5];
    void main() {
        scanf("%d", &N);
        ans[0] = 1;
        rep(i, 1, 55246+45699) {
            ans[i] = (int)(ans[i-1]*19)%998244353;
        }
        rep(i, 1, N) {
            ll val;
            scanf("%lld", &val);
            if (val <= 55246+45699) printf("%d\n", ans[val]);
            else printf("%d\n", ans[(val-55246)%45699+55246]);
        }
    }
}

namespace GG {
    int qpow(int a, int b, int p) {
        int res = 1;
        for (register int k = a; b; k = (ll)k*k%p, b >>= 1)
            if (b & 1) res = (ll)res * k % p;
        return res;
    }
    void run1(int l, int r, int p) {
        if (p == 998244353) {
            rep(i, l, r) if (qpow(i, 499122176, 998244353) != 1 && qpow(i, 142606336, 998244353) != 1 && qpow(i, 58720256, 998244353) != 1) printf("g"); else printf(".");
        } else {
            rep(i, l, r) 
                if (qpow(i, 757671828, 1515343657) != 1 && qpow(i, 505114552, 1515343657) != 1 &&
                    qpow(i, 378552, 1515343657) != 1 && qpow(i, 96072, 1515343657) != 1) printf("g"); else printf(".");
        }
        puts("");
    }
    int st[13123120];
    void run2(int p) {
        memset(st, 0, sizeof(st));
        int g = 6, cnt = 0;
        do {
            cnt++;
            if (cnt % 2 && cnt % 3 && cnt % 5 && cnt % 7 && cnt % 11 && cnt % 13 && cnt % 19 && cnt % 23) st[g] = 1;
            g = g*6%p;
        } while (g != 6);
        rep(i, 1, 13123110) if (st[i]) printf("g"); else printf(".");
        puts("");
    }
}

namespace PP {
    inline ll Mult(ll a, ll b, ll p) {
        ll c = (ll)a*b - (ll)((ull)((long double)a*b/p)*p);
        return c < 0 ? c+p : ((ull)c >= (ull)p ? c-p : c);
    }

    ll qpow(ll a, ll b, ll p) {
        ll res = 1;
        for (register ll k = a; b; k = Mult(k, k, p), b >>= 1)
            if (b & 1) res = Mult(res, k, p);
        return res;
    }
    int test[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    bool MR(ll P, int cnt = 10) {
        ll s = P-1; int t = 0;
        while (!(s & 1)) s >>= 1, t++;
        rep(i, 0, cnt-1) {
            if (P == test[i]) return true;
            if (test[i] > P) return false;
            ll a = qpow(test[i], s, P), nxt;
            rep(x, 1, t) {
                nxt = Mult(a, a, P);
                if (nxt == 1 && a != 1 && a != P-1) return false;
                a = nxt;
                if (a == 1) break;
            }
            if (a != 1) return false;
        }
        return true;
    }
    int N;
    void main() {
        scanf("%d", &N);
        while (N--) {
            ll l, r;
            scanf("%lld%lld", &l, &r);
            while (l <= r) {
                if (MR(l)) printf("p"); else printf(".");
                l++;
            }
            puts("");
        }
    }
}

namespace UU {
    int N;
    int check[1000005], p[100000];
    void init() {
        memset(check, 0, sizeof(check));
        p[0] = 0;
        rep(i, 2, 1000000) {
            if (!check[i]) p[++p[0]] = i;
            for (register int j = 1; j <= p[0] && i*p[j] <= 1000000; j++) {
                check[i*p[j]] = 1;
                if (!(i % p[j])) break;
            }
        }
    }
    ll frac[1000001], mu[1000001];
    bool issqr(ll x) {
        ll v = sqrt(x);
        if (v*v == x || (v-1)*(v-1)==x || (v+1)*(v+1)==x) return true;
        return false;
    }
#define cc(x) ((x) == 0 ? '0' : ((x) < 0 ? '-' : '+'))
    void main() {
        init();
        scanf("%d", &N);
        while (N--) {
            ll l, r;
            scanf("%lld%lld", &l, &r);
            rep(i, 0, r-l) mu[i] = frac[i] = 1;
            rep(i, 1, p[0]) {
                ll x = 1ll*p[i]*p[i], st = l-(l-1)%x-1+x;
                while (st <= r) {
                    mu[st-l] = 0; frac[st-l] = st; st += x;
                }
                x = p[i], st = l-(l-1)%x-1+x;
                while (st <= r) {
                    mu[st-l] = -mu[st-l];
                    if (frac[st-l] != st) frac[st-l] *= x;
                    st += x;
                }
            }
            for (register ll i = l; i <= r; i++) {
                ll val = i/frac[i-l];
                if (val == 1) printf("%c", cc(mu[i-l]));
                else if (PP::MR(val, 2)) printf("%c", cc(-mu[i-l]));
                else if (issqr(val)) printf("0");
                else printf("%c", cc(mu[i-l]));
            }
            puts("");
        }
    }
}

int main() {
    srand(time(0));
    scanf("%s", s);
    if (s[2] == '9') _998244353::main(998244353);
    if (s[1] == '?') {
        if (s[2] == '+') {
            _998244353::main(5211600617818708273ll);
        } else {
            _998244353::main(1145141);
        }
    }
    if (s[1] == 'w') {
        WA::main();
    }
    if (s[1] == 'g') {
        int l, r, p, N;
        if (s[2] == '?') {
            scanf("%d", &N);
            while (N--) {
                scanf("%d%d", &l, &r);
                if (N) scanf("%d", &p); else p = 1515343657;
                GG::run1(l, r, p);
            }
        } else {
            scanf("%d", &N);
            while (N--) {
                scanf("%d%d%d", &l, &r, &p);
                if (p == 998244353) GG::run1(l, r, p);
                else GG::run2(p);
            }
        }
    }
    if (s[1] == 'p') {
        PP::main();
    }
    if (s[1] == 'u') {
        UU::main();
    }

    return 0;
}
相關文章
相關標籤/搜索