Petals linger about

QOJ 19016

感觉很有难度啊。

这种问题,首先因为块内的差分是相等的,所以直接做差分。块间的话,我赛时理解错了,以为 \(c\) 是可变的,实际上并不是,因此差分也是对的。

先考虑怎么对于单块进行判定。

不妨假设块长为 \(h\)。则判定的条件显然为:\(|a_{h+1} - a_1| = 1\),这个等价于差分数组 \(|\sum_{i=1}^h e_i| = 1\),同时满足差分数组 \([L,R-h]=[L+h,R]\) 以及整除的条件显然也是要满足的。我们声称满足这两个条件的块长 \(h\) 为循环块长。

假设现在存在循环块长 \(x,y\),显然满足 \(x+y \le k\)。因此我们有 \(gcd(x,y)\) 同样是满足的。所以我们的最小循环块长 \(p\) 一定是合法块长。再考虑 \(|c|=1\) 的限制,我们不妨假设存在一个块长 \(mp\) 合法,由于循环,我们有 \(m \sum_{i=1}^p e_i = \sum_{i=1}^{mp} e_i\)。因此 \(m=1\) 且 \(|\sum_{i=1}^p| = 1\)。因此我们只需要找到这个 \(p\) 就行了。

考虑怎么找到这个 \(p\),显然 \(h=k\) 时合法,因此我们直接能除就除,复杂度是 \(\log\) 的。

再考虑 \(d\) 的限制。我们发现我们的代码会重复提取同一段序列,我们肯定是要优化的。因此我们对于单个 \(d\) 拆开做。

具体的,定义 \(s_d\) 表示的是公差为 \(d\) 的询问的 \(k\) 的和,如果 \(s_d \le n-d\),代表我们直接提取更优,因此直接提取。否则,代表我们直接做哈希更优,因此直接做哈希。

证明一下这个的复杂度。\(d \le \sqrt n\) 的不超过 \(\sqrt n\) 个,因此做哈希没有问题。\(d \ge \sqrt n\) 的,\(k \le \sqrt n\),因此直接做也是对的。

时间复杂度 \(O(q \sqrt n + q \log n)\)。

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
#define ull unsigned long long
const int N = 1e5 + 10;
int a[N],n;
int ans[N];
struct question{
	int l,r,k;
}ques[N];
vector<int> vec[N];
LL s[N];
int vis[N],pri[N],tot;
void init(){
	for(int i=2;i<=N-10;i++){
		if(vis[i] == 0){
			vis[i] = i;
			pri[++tot] = i;
		}
		for(int j=1;j<=tot;j++){
			if(i * pri[j] > N) break;
			vis[i*pri[j]] = pri[j];
			if(i % pri[j] == 0) break;
		}
	}
	return ;
}
const ull base = 1000003;
const ull base2 = 1000033;
ull pw[N],pw2[N];
ull hsh[N],hsh2[N];
ull get1(int L,int R,int len,int d){
	return hsh[R] - (L - d >= 0 ? hsh[L-d] : 0) * pw[len];
}
ull get2(int L,int R,int len,int d){
	return hsh2[R] - (L - d >= 0 ? hsh2[L-d] : 0) * pw2[len];
}
int main(){
	IOS;
	init();
	cin >> n;
	for(int i=1;i<=n;i++)
		cin >> a[i];
	pw[0] = pw2[0] = 1;
	for(int i=1;i<=n;i++){
		pw[i] = pw[i-1] * base;
		pw2[i] = pw2[i-1] * base2;
	}
	int Q;
	cin >> Q;
	for(int i=1;i<=Q;i++){
		cin >> ques[i].l >> ques[i].r >> ques[i].k;
		int d = (ques[i].r - ques[i].l) / (ques[i].k - 1);
		vec[d].push_back(i);
		s[d] += ques[i].k;
	}
	for(int d=1;d<=n;d++){
		if(vec[d].empty()) continue;
		if(s[d] < n - d){
			for(int id : vec[d]){
				int L = ques[id].l,R = ques[id].r,k = ques[id].k;
				int len = k - 1;
				hsh[0] = hsh2[0] = 0;
				for(int i=1,x=L;i<=len;i++,x+=d){
					hsh[i] = hsh[i-1] * base + (a[x+d] - a[x] + n + 1);
					hsh2[i] = hsh2[i-1] * base2 + (a[x+d] - a[x] + n + 1);
				}
				int p,tmp;p = tmp = k;
				while(tmp > 1){
					int x = vis[tmp];
					while(tmp % x == 0){
						int h = p / x;
						if(k - 1 - h == 0 || get1(1,k-1-h,k-h-1,1) == get1(h+1,k-1,k-h-1,1) && get2(1,k-h-1,k-h-1,1) == get2(h+1,k-1,k-h-1,1))
							p /= x;
						tmp /= x;
					}
				}
				if(p != k && abs(a[p*d+L] - a[L]) == 1)
					ans[id] = 1;
				else ans[id] = 0;
			}
		}
		else{
			hsh[0] = hsh2[0] = 0;
			for(int i=1;i<=n-d;i++){
				hsh[i] = (i > d ? hsh[i-d] : 0) * base + (a[i+d] - a[i] + n + 1);
				hsh2[i] = (i > d ? hsh2[i-d] : 0) * base2 + (a[i+d] - a[i] + n + 1);
			}
			for(int id : vec[d]){
				int L = ques[id].l,R = ques[id].r,k = ques[id].k;
				int len = k - 1;
				int p,tmp;p = tmp = k;
				while(tmp > 1){
					int x = vis[tmp];
					while(tmp % x == 0){
						int h = p / x;
						if(k - 1 - h == 0 || get1(L,R-(h+1)*d,k-h-1,d) == get1(L+h*d,R-d,k-h-1,d) && get2(L,R-(h+1)*d,k-h-1,d) == get2(L+h*d,R-d,k-h-1,d))
							p /= x;
						tmp /= x;
					}
				}
				if(p != k && abs(a[p*d+L] - a[L]) == 1)
					ans[id] = 1;
				else ans[id] = 0;
			}
		}
	}
	for(int i=1;i<=Q;i++){
		if(ans[i]) cout << "Yes\n";
		else cout << "No\n";
	}
	return 0;
}
posted @ 2026-09-20 19:03  WinterXorSnow  阅读(10)  评论(0)    收藏  举报