洛谷 P3674 小清新人渣的本愿
求给定区间内有无两个数的和/差/积为给定的数(两个数可相同)。
首先操作可离线,范围又只有\(10^5\),还是区间问题,又没有什么数据结构维护,那大概就是莫队吧。
我们维护每种数出现次数,记为\(sum_i\)
然后开两个bitset当作bool 数组用,分别统计\(i\)和\(100000 - i\)的值是否存在。
求差:
\[a - b = x \\
a = b + x\\
\]
ans = (bitset1 & (bitset1 << x)).any();
求和:
\[a + b = x \\
a + (100000 - x)= (100000 - b) \\
\]
ans = (bitset2 & (bitset1 << (100000 - x))).any();
求积:
直接对\(x\)分解因数,枚举所有\(\leq \sqrt(x)\)的因数,然后判断\(i\)和\(\frac{i}{x}\)是否存在与bitset1中
#include<bits/stdc++.h>
using namespace std;
const int N = 100050;
int n,m;
int a[N];
struct OP{
int opt,l,r,v,id;
}q[N];
int belong[N],block;
bool cmp(OP a,OP b){
return (belong[a.l] ^ belong[b.l]) ? (belong[a.l] < belong[b.l]) : ( (belong[a.l] & 1) ? a.r < b.r : a.r > b.r );
}
bitset<N> mp1,mp2;//mp1[i] = mp2[100000 - i] 表示i有没有
int sum[N];
int ans[N];
void add(int x){
++ sum[a[x]];
if(sum[a[x]] == 1) mp1[a[x]] = mp2[100000 - a[x]] = 1;
}
void del(int x){
-- sum[a[x]];
if(sum[a[x]] == 0) mp1[a[x]] = mp2[100000 - a[x]] = 0;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; ++ i) scanf("%d",&a[i]);
for(int i = 1; i <= m; ++ i){
scanf("%d%d%d%d",&q[i].opt,&q[i].l,&q[i].r,&q[i].v);
q[i].id = i;
}
block = ceil(sqrt(n));
for(int i = 1; i <= n; ++ i) belong[i] = (i - 1) / block + 1;
sort(q + 1, q + m + 1, cmp);
int L = 1, R = 0;
for(int i = 1; i <= m; ++ i){
while(L < q[i].l) del(L ++);
while(L > q[i].l) add(-- L);
while(R < q[i].r) add(++ R);
while(R > q[i].r) del(R --);
if(q[i].opt == 1){//a - b = v -> a = b + v
ans[q[i].id] = (mp1 & (mp1 << q[i].v)).any();
}
if(q[i].opt == 2){//a + b = v -> a = v - b -> a = (100000 - b) - (100000 - v)
ans[q[i].id] = (mp1 & (mp2 >> (100000 - q[i].v)) ).any();
}
if(q[i].opt == 3){
for(int j = 1; 1ll * j * j <= q[i].v; ++ j){
if(q[i].v % j) continue;
int x = j, y = q[i].v / j;
ans[q[i].id] = mp1[x] & mp1[y];
if(ans[q[i].id]) break;
}
}
/*if(a[i].opt == 4){
}*/
}
for(int i = 1; i <= m; ++ i)
puts(ans[i] ? "hana" : "bi" );
return 0;
}