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);
}
}