4810: [Ynoi2017]由乃的玉米田
Time Limit: 30 Sec Memory Limit: 256 MB
Submit: 622 Solved: 306
[Submit][Status][Discuss]
Description
由乃在自己的农田边散步,她突然发现田里的一排玉米非常的不美。这排玉米一共有N株,它们的高度参差不齐。
由乃认为玉米田不美,所以她决定出个数据结构题
这个题是这样的:
给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是
否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1
,2,3选出的这两个数可以是同一个位置的数
Input
第一行两个数n,m
后面一行n个数表示ai
后面m行每行四个数opt l r x
opt表示这个是第几种操作,l,r表示操作的区间,x表示这次操作的x
定义c为每次的x和ai中的最大值,ai >= 0,每次的x>=2n,m,c <= 100000
Output
对于每个询问,如果可以,输出yuno,否则输出yumi
Sample Input
5 5
1 1 2 3 4
2 1 1 2
1 1 2 2
3 1 1 1
3 5 5 16
1 2 3 4
Sample Output
yuno
yumi
yuno
yuno
yumi
HINT
Source
By 佚名提供
[Submit][Status][Discuss]
几句闲话
信了出题人的[Ynoi2017]…还以为真的是云南省选的题目,实际上是由乃oi…身为oi人,怎能不看番.
题解
这道题确实算是一道好题(绝绝绝绝对不是因为出题人是学长的关系).
当询问一个区间的时候,我们要想起莫队.
当询问非指定的数加减的时候,我们要想起bitset.
当询问乘积的时候…我我我我我们要想起暴力.
这道题考虑离线处理莫队(在线不好搞啊,还是orz莫队吧).怎么进行区间o(1)转移?我们都知道莫队在一步一步从当前区间靠近下一个询问区间的时候,每次挪一步只与之前的区间有一个元素之差.我们用一个c数组维护区间每个元素权值的出现次数,每次挪一步的时候update这个唯一改变的元素(update见代码).
挪到了我们要询问的区间了,怎么给出答案?
对当前区间用一个bitset来维护某权值出没出现过.
对于相减为x,即区间内a[i]-a[j]为x,相当于将原区间的bitset右移x位(减)与原来&一下看还有没有某位上为1,解释一下假设区间内符合上等式a[i]存在(bitset那一位为1,表示存在这个权值), a[j]存在 (1),那a[i]右移x位的值就是aj,与原来移位之前这位上的a[j]相&,1&1=1,所以只需看看1存在没有就可以了.否则两者至少有一个在区间内不存在(0),1&0=0||0&0=0,无1存在.(注意bitset是整个全部移).
对于相加为x,我们肯定想用一样的思路.但是这个为a[i]+a[j]=x,a[i]和a[j]都为不定量,没法移。所以我们想到将这个等式变换.两边同时减一个c:
a[i]+a[j]-c=x-c -> c-a[j]=a[i]-(c-x).我们发现我们只需要另外维护一个bitset去维护c-a[i],就跟上面相减一样的了,只是每次移位为c-x了,注意c肯定要大于a数组所有的值(要为正值)可取100005(由数据范围可得).对于相乘…直接枚举x的因子暴力即可…
#include<stdio.h>
#include<cmath>
#include<bitset>
#include<algorithm>
using namespace std;
const int maxn=100010;
bitset<maxn> T,A,B;
bool ans[maxn<<2];
int block,n,m;
int a[maxn],b[maxn],c[maxn],blo[maxn];
inline const int read(){
register int f=1,x=0;
register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return f*x;
}
struct query{
int l,r,x,opt,id;
}q[maxn];
inline bool cmp(query a,query b){if(blo[a.l]==blo[b.l])return a.r<b.r;return blo[a.l]<blo[b.l];}
inline void update(int x,int val){
c[a[x]]+=val;
if(val^-1){
if(c[a[x]]==1) A[a[x]]=B[b[x]]=1;
return;
}
if(!c[a[x]]) A[a[x]]=B[b[x]]=0;
}
inline bool query(query& d){
if(d.opt==1){
T=A;
T>>=d.x,T&=A;
if(T.count()) return true;
return false;
}
if(d.opt==2){
T=B;
T>>=(maxn-d.x),T&=A;
if(T.count()) return true;
return false;
}
int top=sqrt(d.x)+1;
for(int i=1;i<=top;i++)
if(!(d.x%i)&&c[i]&&c[d.x/i]) return true;
return false;
}
inline void Mo_Dui(){
for(int i=1,l=1,r=0;i<=m;i++){
while(r<q[i].r) update(++r,1);
while(r>q[i].r) update(r--,-1);
while(l>q[i].l) update(--l,1);
while(l<q[i].l) update(l++,-1);
ans[q[i].id]=query(q[i]);
}
}
int main(){
n=read(),m=read();
for(register int i=1;i<=n;i++) a[i]=read(),b[i]=maxn-a[i];
block=sqrt(n);
for(register int i=1;i<=n;i++) blo[i]=(i-1)/block+1;
for(register int i=1;i<=m;i++) q[i].opt=read(),q[i].l=read(),q[i].r=read(),q[i].x=read(),q[i].id=i;
sort(q+1,q+m+1,cmp);
Mo_Dui();
for(int i=1;i<=m;i++) puts(ans[i]?"yuno":"yumi");
}