给你一个序列 aaa,长度为 nnn,有 mmm 次操作,每次询问一个区间是否可以选出两个数它们的差为 xxx,或者询问一个区间是否可以选出两个数它们的和为 xxx,或者询问一个区间是否可以选出两个数它们的乘积为 xxx ,或者询问一个区间是否可以选出两个数它们的商为 xxx(没有余数) ,这四个操作分别为操作 1,2,3,41,2,3,41,2,3,4。
选出的这两个数可以是同一个位置的数。
数据范围\(1e5\)
莫队+bitset维护每个值是否出现
注意0的特判情况
减法:
a-b=x
a=b+x;
于是按位与\(bit\&(bit<<x)\)若有值则可行
加法:
a-(n-b)=x-n
a=(n-b)-x+n
于是莫队时再维护一个反的序列
\(ans=(bit\&(bit2>>n-x)).any()\)
乘法:
\(\sqrt n\)暴力判
整除:
数据分块
\(x>\sqrt n\)暴力判
\(x<\sqrt n\)每个x的询问集中单独算,移右端点算左端点,树状数组维护
时间复杂度\(O(n\sqrt n\log n+\frac{n^2}w)\)
//starusc
/*
数据不清空,爆零两行泪。
多测不读完,爆零两行泪。
边界不特判,爆零两行泪。
贪心不证明,爆零两行泪。
D P 顺序错,爆零两行泪。
大小少等号,爆零两行泪。
变量不统一,爆零两行泪。
越界不判断,爆零两行泪。
调试不注释,爆零两行泪。
溢出不 l l,爆零两行泪。
*/
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x=0,f=1;
char c=getchar();
while(!isdigit(c)) {
if(c==‘-‘)f=-1;
c=getchar();
}
while(isdigit(c)) {
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return f==1?x:-x;
}
const int N = 1e5+4, B = 400;
int n, m, a[N], ans[N], cnt[N];
struct ques {
int op, l, r, v, id;
} q[N];
inline bool comp (const ques &x, const ques &y) {
return x.l/B == y.l/B ? (((x.l/B)&1) ? x.r < y.r : x.r > y.r) : x.l/B < y.l/B;
}
bitset<N>b,rb;
inline bool comp_2(const ques &x,const ques &y){
return x.r<y.r;
}
int t[N],tmp[N];
vector<ques>que[B];
inline void add(int x,int v){
for(;x<=n;x+=x&-x)t[x]+=v;
}
inline int ask(int x){
int ret=0;
for(;x;x-=x&-x)ret+=t[x];
return ret;
}
inline void solve(int c){
if(que[c].empty())return;
sort(que[c].begin(),que[c].end(),comp_2);
int nw=1;
for(auto v:que[c]){
while(nw<=n&&nw<=v.r){
if(tmp[a[nw]]){
add(1,1);add(tmp[a[nw]]+1,-1);
}
if(a[nw]*c<=N-4)tmp[a[nw]*c]=nw;
if(a[nw]%c==0)tmp[a[nw]/c]=nw;
nw++;
}
ans[v.id]|=(ask(v.l)>0);
}
memset(t,0,sizeof(t));
memset(tmp,0,sizeof(tmp));
}
int main() {
n = read();
m = read();
for(int i = 1; i <= n; ++i) a[i] = read();
for(int i = 1; i <= m; ++i) {
q[i].op = read();
q[i].id = i;
q[i].l = read();
q[i].r = read();
q[i].v = read();
}
sort(q + 1, q + m + 1, comp);
for(int i = 1, nl = 1, nr = 0; i <=m ; ++i) {
while(nr < q[i].r) {
nr++;
if(!cnt[a[nr]]) {
b[a[nr]] = 1;
rb[N-4-a[nr]] = 1;
}
cnt[a[nr]]++;
}
while(nl > q[i].l) {
nl--;
if(!cnt[a[nl]]) {
b[a[nl]] = 1;
rb[N-4-a[nl]] = 1;
}
cnt[a[nl]]++;
}
while(nr > q[i].r) {
cnt[a[nr]]--;
if(!cnt[a[nr]]) {
b[a[nr]] = 0;
rb[N-4-a[nr]] = 0;
}
nr--;
}
while(nl < q[i].l) {
cnt[a[nl]]--;
if(!cnt[a[nl]]) {
b[a[nl]] =0 ;
rb[N-4-a[nl]] =0 ;
}
nl++;
}
if(q[i].op == 1) ans[q[i].id] = (b & (b << q[i].v)).any();
else if(q[i].op == 2) ans[q[i].id] = ((b << N-4-q[i].v) & rb).any();
else if(q[i].op == 3) {
if(!q[i].v)ans[q[i].id]=b[0];
else for(int j = 1; j * j <= q[i].v; ++j) {
if(q[i].v % j)continue;
if(b[j] && b[q[i].v / j]) {
ans[q[i].id] = 1;
break;
}
}
}
else{
if(!q[i].v)ans[q[i].id]=b[0]&&b.count()>1;
else if(q[i].v==1)ans[q[i].id]=(b.count()-b[0])>0;
else if(q[i].v>=B){
for(int j=1,j2=q[i].v;j2<=N-4;j++,j2+=q[i].v)
if(b[j]&&b[j2]){
ans[q[i].id]=1;
break;
}
}
else que[q[i].v].push_back(q[i]);
}
}
for(int i=2;i<B;i++)solve(i);
for(int i = 1; i <= m; ++i)
puts(ans[i] ? "yuno" : "yumi");
return (0-0);
}
原文:https://www.cnblogs.com/aurora2004/p/12989430.html