Heretical … Möbius【18EC】

Heretical … Möbius

有一个序列

[f = igg | mu(i) igg |, i = 1,2,3,...,1e9 ]

给一个长度为 200 的子序列,该子序列在 (f) 中第一次出现的位置,若没有出现过,则输出 -1

思路

首先, (ig | mu(x) ig |)(x) 被某个数的平方整除的话则为 0 ,否则就是 1

因为序列的长度只有 200 , 考虑 200 以内的质数平方序列 4,9,25,49,121,169

可以暴力枚举起始位置对这六个数的模数

虽然 (M = 4*9*25*49*121*169 = 901800900 ≈ 9e8)

但是我们并不需要全部枚举出来,因为很多模数不合法。这里合法直接 (O(200)) 判断就好

枚举完之后,用 (CRT) (中国剩余定理) 计算出初始位置 (x) , 注意此时的 (x) 未必合法,因为其余位置未必都是 1 , 所以还需要计算 ([x,x + 199])(200) 个数的 (ig |mu(i) ig |)

,注意还需要继续在 (1e9) 范围内继续枚举 (x + M)

int mu(int v) {
    for (int i = 1; i <= cnt and prime[i] * prime[i] <= v; i++) {
        if (v % (prime[i] * prime[i]) == 0)return 0;

        if (v % prime[i] == 0)v /= prime[i];
        //我大意了啊,没有加这一行, TLE 了一个晚上 /wx
    }
    return 1;
}

这里 取模运算是一种很慢的运算, 而这个函数又是在 (dfs) 的低端调用,所以这个函数调用次数巨大。不加那一行会变得巨慢 ,真的长知识了

还有一个地方就是计算的开始位置是 (x) 的话, 要判断 (x + 199) 是否在 (1e9) 范围内

否则不合法

还需要对 0 的数量做一个大概的合理估计,很显然可以估出一个下界 50 ,因为用 4 就可以筛出这么多,可以凭感觉估一个 100 ,其实可以稍微做一下计算

L = [4,9,25,49,121,169]
ans = 0
for i in L:
    ans += 200 // i
ans
>>> 86
/*
 * @Author: zhl
 * @LastEditTime: 2020-11-30 21:22:38
 */
#include<bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
using namespace std;

void ex_gcd(int a, int b, int& gcd, int& x, int& y) {
    if (b == 0) {
        x = 1;
        y = 0;
        gcd = a;
    }
    else {
        ex_gcd(b, a % b, gcd, y, x);
        y -= x * (a / b);
    }
}

const int M = 901800900;
const int m[] = { 0,4,9,25,49,121,169 };
int a[10], ti[10];
int CRT() {
    int res = 0;
    int x, y, gcd;

    for (int i = 1; i <= 6; i++) {
        int tmp = M / m[i];
        ex_gcd(tmp, m[i], gcd, x, y);
        x = (x % m[i] + m[i]) % m[i];
        ti[i] = x * tmp;
        res = (res + tmp * a[i] * x) % M;
    }
    return (res + M) % M;
}

char s[300];
bool ok(int r, int mod) {
    int st = r == 0 ? 1 : 1 - r + mod;
    while (st <= 200) {
        if (s[st] != '0')return false;
        st += mod;
    }
    return true;
}
int ans;
int prime[100010], cnt, vis[100010];
void init() {
    for (int i = 2; i <= 100000; i++) {
        if (not vis[i])prime[++cnt] = i;
        for (int j = 1; j <= cnt and prime[j] * i <= 100000; j++) {
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0)break;
        }
    }
}
int mu(int v) {
    for (int i = 1; i <= cnt and prime[i] * prime[i] <= v; i++) {
        if (v % (prime[i] * prime[i]) == 0)return 0;
        if (v % prime[i] == 0)v /= prime[i];
    }
    return 1;
}
bool judge(int v) {
    for (int i = 1; i <= 200; i++) {
        if (mu(v + i - 1) != s[i] - '0')return false;
    }
    return true;
}
void dfs(int now) {
    if (now == 7) {
        /*for (int i = 1; i <= 6; i++) {
            cout << a[i] << endl;
        }*/
        int v = CRT();
        if (v == 0)v = M;
        while (v + 199 <= 1e9 and v < ans) {
            if (judge(v)) ans = v;
            v += M;
        }
        return;
    }

    for (int i = 0; i < m[now]; i++) {
        if (not ok(i, m[now]))continue;
        a[now] = i;
        dfs(now + 1);
    }
}
signed main() {
    init();
    for (int i = 1; i <= 10; i++) {
        scanf("%s", s + i * 20 - 20 + 1);
    }
    int ct = 0; for (int i = 1; i <= 200; i++)if (s[i] == '0')ct++;
    if (ct < 50 or ct > 100)puts("-1");
    else {
        //printf("%s
", s + 1);
        ans = 1e9;
        dfs(1);
        if (ans == 1e9)puts("-1");
        else printf("%lld
", ans);
    }
}
原文地址:https://www.cnblogs.com/sduwh/p/14063734.html