Description
现在有一个长度为(~n~)的数列(~A_1~,~A_2~dots~A_n~),(~Q~)个询问(~[l_i~,~r_i]~),每次询问区间内是否有元素相同
Input
第一行有两个整数(~N,Q~),
第二行有(~n~)个整数,代表这个序列
以下(~Q~)行每行两个整数,代表询问区间
Output
对每个询问输出一行(~Yes~)或(~No~)。
Hint
(Forall:)
(1~leq~n~,~Q~leq~10^5~,~1~leq~A_i~leq~N~,~1~leq~l_i~leq~r_i~leq~N)
Solution
看到这题发现可以用莫队做。然鹅统计区间出现次数平方的题写腻了,而开桶和位向量的做法又很麻烦,于是我就YY了一个更加麻烦的做法。
发现我们可以在莫队维护区间信息的时候维护区间中所有元素出现次数之积。因为乘1等价于没有乘,我们对于没有出现的元素也乘1。这个值在指针移动时是支持修改的:只要在去掉该位置贡献的时候除掉当前的出现次数,然后将这个位置的出现次数(-1),再乘回去即可。增加一个位置贡献的方法同理。当询问的区间出现次数积为(1)时,即为没有出现重复,否则为出现重复。
但是考虑这么做在极端数据,比如前(frac{n}{2})个数出现了(2)次,后(frac{n}{2})个数没有出现的时候,积是(2^{frac{n}{2}})次方,显然存不下。这时考虑NOIP2014解方程,我们只需要对多个形如1******7的大质数取模,当所有取模后的答案都为(1)是,我们认为积是(1),否则积显然不是(1)。
于是先(O(n))筛一下逆元再莫队就好了。
Code
这个代码写的好丑啊……其实可以美化美化然而我懒得写了
#include<cmath>
#include<cstdio>
#include<algorithm>
#ifdef ONLINE_JUDGE
#define puts(o)
puts("I am a cheater!")
#define freopen(a,b,c)
#endif
#define rg register
#define ci const int
#define cl const long long
typedef long long int ll;
template <typename T>
inline void qr(T &x) {
rg char ch=getchar(),lst=' ';
while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst == '-') x=-x;
}
namespace IO {
char buf[120];
}
template <typename T>
inline void qw(T x,const char aft,const bool pt) {
if(x < 0) {x=-x,putchar('-');}
rg int top=0;
do {IO::buf[++top]=x%10+'0';} while(x/=10);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
}
const int maxn = 100010;
const int ccnt = 6;
int n,q;
int MU[maxn],belong[maxn],bk[maxn];
int inv[8][maxn];
struct Ask {
int l,r,num;
bool ans;
inline bool operator<(const Ask &_others) const {
if(belong[this->l] != belong[_others.l]) return this->l < _others.l;
if(belong[this->l] & 1) return this->r < _others.r;
else return this->r > _others.r;
}
};
Ask ask[maxn];
inline bool cmp(const Ask &_a,const Ask &_b) {
return _a.num < _b.num;
}
struct C {
int mod;
int ans;
C(int _x=0) {mod=_x,ans=1;}
};
C CU[8];
void GetInv(ci,ci);
int main() {
freopen("1.in","r",stdin);
qr(n);qr(q);
for(rg int i=1;i<=n;++i) qr(MU[i]);
for(rg int i=1,sn=sqrt(n);i<=n;++i) belong[i]=i/sn;
for(rg int i=1;i<=q;++i) {
qr(ask[i].l);qr(ask[i].r);ask[i].num=i;
}
CU[1]=C(1000000007);CU[2]=C(1000000009);CU[3]=C(19260817);CU[4]=C(998244353);CU[5]=C(10000007);
for(int i=1;i<ccnt;++i) GetInv(CU[i].mod,i);
std::sort(ask+1,ask+1+q);
int prel=ask[1].l,prer=ask[1].l-1;
#define jd(o) (bk[MU[o]] > 1)
for(rg int i=1;i<=q;++i) {
int l=ask[i].l,r=ask[i].r;
while(prel < l) {
if(jd(prel)) {
for(rg int j=1;j<ccnt;++j) CU[j].ans=1ll*CU[j].ans*inv[j][bk[MU[prel]]]%CU[j].mod;
}
--bk[MU[prel]];
if(jd(prel)) {
for(rg int j=1;j<ccnt;++j) CU[j].ans=1ll*CU[j].ans*bk[MU[prel]]%CU[j].mod;
}
++prel;
}
while(prel > l) {
--prel;
if(jd(prel)) {
for(rg int j=1;j<ccnt;++j) CU[j].ans=1ll*CU[j].ans*inv[j][bk[MU[prel]]]%CU[j].mod;
}
++bk[MU[prel]];
if(jd(prel)) {
for(rg int j=1;j<ccnt;++j) CU[j].ans=1ll*CU[j].ans*bk[MU[prel]]%CU[j].mod;
}
}
while(prer < r) {
++prer;
if(jd(prer)) {
for(rg int j=1;j<ccnt;++j) CU[j].ans=1ll*CU[j].ans*inv[j][bk[MU[prer]]]%CU[j].mod;
}
++bk[MU[prer]];
if((jd(prer))) {
for(rg int j=1;j<ccnt;++j) CU[j].ans=1ll*CU[j].ans*bk[MU[prer]]%CU[j].mod;
}
}
while(prer > r) {
if(jd(prer)) {
for(rg int j=1;j<ccnt;++j) CU[j].ans=1ll*CU[j].ans*inv[j][bk[MU[prer]]]%CU[j].mod;
}
--bk[MU[prer]];
if(jd(prer)) {
for(rg int j=1;j<ccnt;++j) CU[j].ans=1ll*CU[j].ans*bk[MU[prer]]%CU[j].mod;
}
--prer;
}
bool _ans=true;
for(rg int j=1;j<ccnt;++j) if(CU[j].ans != 1) {
_ans=false;break;
}
ask[i].ans=_ans;
}
#undef jd
std::sort(ask+1,ask+1+q,cmp);
for(rg int i=1;i<=q;++i)
if(ask[i].ans) puts("Yes");
else puts("No");
return 0;
}
void GetInv(ci mod,ci cur) {
inv[cur][1]=1;
for(rg int i=2;i<=n;++i) inv[cur][i]=1ll*(mod-mod/i)*inv[cur][mod%i]%mod;
}
Summary
貌似这次没啥好summary的