C. Heretical … Möbius

const int N = 1e9;
int p[1010], cnt;
bool vis[1010];
unordered_set<int> st;
char s[205];
ll pri[] = { 2,3,5,7,11,13 };
vector<int> g[6];
ll a[6];
void get() {
	f(i, 2, 1009) {
		if (!vis[i])p[++cnt] = i;
		for (int j = 1;p[j] <= 1009 / i;j++) {
			vis[p[j] * i] = true;
			if (i%p[j] == 0)break;
		}
	}
}
void get_2() {
	for (int j = p[cnt];j*j <=N;j++) {
		for (int i = j * j;i <= N;i += j * j)st.insert(i);
	}
}
bool check(int a, int b) {
	for (int i = 0;b + i * a < 200;i++) {//%a==b,情况
		if (s[b + i * a] == '1')return false;
	}
	return true;
}
pair<ll,ll> china(int n, ll *a, ll *m) {
	ll M = 1, ret = 0;
	for (int i = 0; i < n; i++) M *= m[i];
	for (int i = 0; i < n; i++) {
		ll w = M / m[i];
		ret = (ret + w * inv(w, m[i]) * a[i]) % M;
	}
	return pair<ll,ll>{ (ret + M) % M,M };
}
bool ch2(int x) {//无平方因子则false
	f(i, 1, cnt) {
		if (x % (p[i] * p[i]) == 0)return true;
	}
	return st.count(x);
}
bool ch1(int st) {
	f(i, 0, 199) {
		if (s[i]=='0'&&!ch2(st + i))return false;
		else if (s[i] == '1'&&ch2(st + i))return false;
	}
	return true;
}
ll cal() {
	//检查满足当前的组合等价类
	pair<ll, ll> t = china(6, a, pri);
	if (ch1(t.first))return t.first;
	if ((t.first + t.second + 199) <= N && ch1(t.first + t.second))return { t.second + t.first };
	//debug((2e18));
	return 2e18;
}
ll ans = 2e18;
void dfs(int x) {
	if (x == 6) {
		ans = min(ans, cal());
		return;
	}
	else {
		for (auto i : g[x]) {
			a[x] = i;
			dfs(x + 1);
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	//1e9!!!!!!!是不是很神奇?
	//题意:现在已知一个长度为200的字符串t可能是,1到1e9的数的莫比乌斯函数绝对值
	//构成的字符串的子串
	//问你是否可能是s的子串,如果可能输出在s中第一次出现的位置。
	//因为这里的u函数取了绝对值,我们的关注点放在一个数是否有平方因子,
	//即有素数因子的次数大于等于2,如果有就是0,否则就是1
	//一开始,我们会发现这道题完全没有突破口,因为这道题的范围实在是太大了
	//1.首先,我们需要知道的是如何高效求1e9范围内的一个数是否有平方因子
	//首先直接预处理1e9质数必死,那么考虑我们的枚举倍数算法,n*logn,显然
	//还是用不了的,那么牛逼的操作就来了考虑先对小部分小的质数直接暴力判断
	//然后从一个较大的质数开始,枚举它的平方,以及它的平方的倍数这样每次只要169+log(6e5)
	//2.但是关键的问题还是没解决,如何在1e9内找一个长度为200的子串呢
	//牛逼的思想又来了,其实问题的关键在于确定我们子串的开始位置
	//我们可以发现如果我们将1e9的数按模4的意义分类,首先我们可以直接判断以这个
	//模意义下的数开头的数是否是可以有解的,无解就直接干死,因为假如我们pos为4的
	//倍数,那么pos+4的位置也是4的倍数,我们拿这个值去与原子串比较判断,如果
	//这个都不行,表明以%4为某个数的数开头是必定无解的,这样我们就起到了剪枝
	//有意义的话就从小的到大枚举等价类,4->8->12,我们发现这个过程也是很漫长的
	//能不能再优化呢,于是乎骚操作来了,无敌优美的凹曲线。
	//我们光考虑一个2*2,发现等价类还是很多,那么就多几个质数,使得等价类变少
	//901800900,当我们取到6个质数时就会发现,我们最多只需要算两次等价类
	//ok大致思路确定正确后,就可以处理出题目给我们的t对这6个质数的哪些模意义下
	//有解把,6个质数的莫意义最多有30030种组合,对于每种组合我们要去判断200个数
	//每次判断内部大概也需要169+log(6e5)去检查,当然这是最最最坏的情况,感性的来说
	//你不给这复杂度除个10?哦,3e8那就可以过了
	//ll lcm = 1ll * 4 * 9 * 25 * 49 * 121 * 169;
	get();//169
	get_2();//6e5
	f(i, 1, 10) {
		scanf("%s", s + (i-1) * 20);//0-199
	}
	f(i, 0, 5)pri[i] *= pri[i];
	f(i, 0, 5){ 
		f(j, 0, pri[i] - 1) {//检查在模每个质数意义下是否成立
			if (check(pri[i], j))g[i].emplace_back(pri[i]-j);
		}
	}
	int num = 0;
	f(i, 0, 199) {
		if (s[i] == '0')num++;
	}
	if (num >= 100) {
		puts("-1");
		return 0;
	}
	/*f(i, 0, 5) {
		for (auto u : g[i])cout << u << " ";
		cout << endl;
	}*/
	//减掉了一些必死的模意义组合
	//开始枚举每种组合
	dfs(0);
	if (ans == 2e18)puts("-1");
	else cout << ans << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值