莫队专题

https://blog.csdn.net/qq_41552508/article/details/100556943附上学习连接

以防万一还是搬出来吧

一、适用问题

莫队算法是一种离线算法,用分块去优化暴力,不包含修改的话,复杂度为 O(nn−−√+mn−−√) O(n\sqrt n+m\sqrt n)O(n

n

?

+m

n

?

),n nn 为序列长度,m mm 为操作总数。

二、算法实现

莫队本质上就是用分块去优化暴力的离线算法,将总复杂度降到 O(nn−−√) O(n\sqrt n)O(n

n

?

) 的位置。说白了,就是分块+暴力。

我们先讲暴力的部分。比如一个长度为 n nn 的序列,m mm 次查询,每次查询询问区间 [l,r] [l,r][l,r] 之间的众数。对于这个问题,暴力求的话就是直接用桶记录每个数出现的次数,然后遍历区间 [l,r] [l,r][l,r],直接统计答案即可。这个暴力过程和莫队暴力过程没有任何区别,然后问题就变成了如何用分块来优化这个暴力呢?

在分块的部分,该算法将整个序列按照 n−−√ \sqrt n

n

?

大小进行分块,共分成 n−−√ \sqrt n

n

?

块,然后对于所有的询问,先按照左端点所在的块编号进行排序,如果块编号相同,再按照右端点排序。询问排序完之后,就直接暴力求解即可。代码的话看一下下面习题就可以掌握了。

最后就是时间复杂度的问题了。如何证明这个算法的时间复杂度呢?我们对每一个块分开进行考虑,假设有 bi b_ib

i

?

次操作在第 i ii 个块中,则在这个块中,右端点一定递增,因此右端点最多移动 n nn 次,而左端点每次最多移动 n−−√ \sqrt n

n

?

,一共最多移动 bi∗n−−√ b_i*\sqrt nb

i

?

n

?

次,每次端点移动的时间复杂度为 O(1) O(1)O(1),因此移动的总次数为 ∑n√i=1(bi∗n−−√+n)=m∗n−−√+n∗n−−√ \sum\limits_{i=1}^{\sqrt n}(b_i*\sqrt n+n)=m*\sqrt n+n*\sqrt n

i=1

n

?

?

(b

i

?

n

?

+n)=m∗

n

?

+n∗

n

?

,因此总复杂度为 O(nn−−√+mn−−√) O(n\sqrt n+m\sqrt n)O(n

n

?

+m

n

?

)。

三、普通莫队习题

1. [2009国家集训队] 小Z的袜子

题意: n nn 双颜色不同袜子,m mm 次询问,每次询问给出 [L,R] [L,R][L,R] 区间,询问在 [L,R] [L,R][L,R] 区间中随机抽出两双颜色相同的袜子的概率,输出最简分数形式 (A/B) (A/B)(A/B)。

?我们所记录的是x双同色袜子的组合方案数所以我们除以他的区间内袜子的c(n,2)就是答案了

分析到这里,就可以发现这是一道普通莫队的裸题,我们添加与删除时只需加上或减去当前与该点颜色相同的袜子数,这样同时可以避免重复计算。

代码:

#include <bits/stdc++.h>

#define rep(i,a,b) for(int i = a; i <= b; i++)

typedef long long ll;

const int N = 2*1e5+100;

using namespace std;

int a[N],pos[N],n,m,L,R;

ll ans[N][2],flag[N],Ans;

struct Node{

int l,r,id;

bool operator < (Node xx) const{

if(pos[l] == pos[xx.l]) return r < xx.r;

else return pos[l] < pos[xx.l];

}

}Q[N];

ll gcd(ll a,ll b) {return b == 0 ? a:gcd(b,a%b);}

void add(int x){

Ans += flag[a[x]];

flag[a[x]]++;

}

void del(int x){

flag[a[x]]--;

Ans -= flag[a[x]];

}

int main()

{

L = 1, R = 0;

scanf("%d%d",&n,&m);

int sz = sqrt(n);

rep(i,1,n){

scanf("%d",&a[i]);

pos[i] = i/sz;

}

rep(i,1,m){

scanf("%d%d",&Q[i].l,&Q[i].r);

Q[i].id = i;

}

sort(Q+1,Q+1+m);

rep(i,1,m){

while(L < Q[i].l) del(L),L++;

while(L > Q[i].l) L--, add(L);

while(R < Q[i].r) R++, add(R);

while(R > Q[i].r) del(R), R--;

ll len = Q[i].r-Q[i].l+1;

ll tp = len*(len-1ll)/(ll)2;

ll g = gcd(Ans,tp);

ans[Q[i].id][0] = Ans/g;

ans[Q[i].id][1] = tp/g;

}

rep(i,1,m) printf("%lld/%lld\n",ans[i][0],ans[i][1]);

return 0;

}

2. 花神的嘲讽计划Ⅰ

题意: 初始序列长度为 n nn,m mm 组询问,每次询问给出一个 x xx、y yy,以及长度为 k kk 的连续序列。询问在区间 [x,y] [x,y][x,y] 中是否存在一段连续的长度为 k kk 的,与询问中给出的序列相同的一段序列。存在输出 No NoNo,不存在输出 Yes YesYes。(1≤n,m≤106) (1\leq n,m\leq 10^6)(1≤n,m≤10

6

)

思路: 这题可以观察到每次询问的连续序列长度都是固定为 k kk,因此不难想到用 hash hashhash 来解决这个问题。我们将每个位置后面连续的一段 k kk 哈希起来,然后每个位置就有了一个对应的 hash hashhash 值。我们将这些 hash hashhash 值离散化之后,用桶来记录区间端点移动时对答案的贡献。

代码:

#include <bits/stdc++.h>

#define rep(i,a,b) for(int i = a; i <= b; i++)

typedef long long ll;

const int N = 2*1e6+100;

const ll mod = 1e11+7;

using namespace std;

int n,m,k,L,R,flag[N],tot,ans[N],pos[N],pp[N];

ll a[N],b[N],ha[N];

struct Node{

int l,r,id;

ll w;

bool operator < (Node xx) const {

if(pos[l] != pos[xx.l]) return pos[l] < pos[xx.l];

else return r < xx.r;

}

}q[N];

int find(ll x){

return lower_bound(b+1,b+1+tot,x)-b;

}

ll Hash(int pos){

ll tp = 0;

ll base = 1;

rep(i,pos,pos+k-1){

tp = (tp+a[i]*base)%mod;

if(tp < 0) tp = (tp+mod)%mod;

base = (base*(ll)133)%mod;

if(base < 0) base = (base+mod)%mod;

}

return tp;

}

void add(int x) {flag[pp[x]]++;}

void del(int x) {flag[pp[x]]--;}

int main()

{

scanf("%d%d%d",&n,&m,&k);

rep(i,1,n) scanf("%lld",&a[i]);

rep(i,1,m){

int xx,yy; scanf("%d%d",&xx,&yy);

q[i].l = xx, q[i].r = yy, q[i].id = i;

q[i].r = q[i].r-k+1;

ll tp = 0;

ll base = 1;

rep(j,1,k){

ll hp; scanf("%lld",&hp);

tp = (tp+hp*base)%mod;

if(tp < 0) tp = (tp+mod)%mod;

base = (base*(ll)133)%mod;

if(base < 0) base = (base+mod)%mod;

}

q[i].w = tp;

b[++tot] = tp;

}

rep(i,1,n-k+1){

ll tp = Hash(i);

ha[i] = tp;

b[++tot] = tp;

}

sort(b+1,b+1+tot);

tot = unique(b+1,b+1+tot)-b-1;

rep(i,1,n-k+1){

pp[i] = find(ha[i]);

}

int sz = sqrt(n);

rep(i,1,n) pos[i] = i/sz;

sort(q+1,q+1+m);

L = 1, R = 0;

rep(i,1,m){

while(L < q[i].l) del(L), L++;

while(L > q[i].l) L--, add(L);

while(R < q[i].r) R++, add(R);

while(R > q[i].r) del(R), R--;

int pos = find(q[i].w);

if(flag[pos]) ans[q[i].id] = 1;

else ans[q[i].id] = 0;

}

rep(i,1,m){

if(ans[i]) printf("No\n");

else printf("Yes\n");

}

return 0;

}

3. XOR and Favorite Number

思路: 既然是某一区间的异或和,不难想到先求一个异或前缀和,然后对于一个 j jj 来说,就是询问区间 [l,r] 中有多少个 i i 满足 sum[i−1]  ^ sum[j]=k。

问题拆解到这一步,剩下的问题就比较明了了,直接上莫队,然后用桶维护每一个数的异或前缀和即可。

代码:

#include <bits/stdc++.h>

#define rep(i,a,b) for(int i = a; i <= b; i++)

typedef long long ll;

const int N = 2*1e6+100;

using namespace std;

int a[N],pos[N],n,m,k,L,R;

ll ans[N],flag[N],Ans;

struct Node{

int l,r,id;

bool operator < (Node xx) const{

if(pos[l] == pos[xx.l]) return r < xx.r;

else return pos[l] < pos[xx.l];

}

}Q[N];

void add(int x){

Ans += flag[a[x]^k];

flag[a[x]]++;

}

void del(int x){

flag[a[x]]--;

Ans -= flag[a[x]^k];

}

int main()

{

L = 1, R = 0;

scanf("%d%d%d",&n,&m,&k);

int sz = sqrt(n);

rep(i,1,n){

scanf("%d",&a[i]);

a[i] = a[i]^a[i-1];

pos[i] = i/sz;

}

rep(i,1,m){

scanf("%d%d",&Q[i].l,&Q[i].r);

Q[i].id = i;

}

sort(Q+1,Q+1+m);

flag[0] = 1;

rep(i,1,m){

while(L<Q[i].l) del(L-1), L++;

while(L>Q[i].l) L--, add(L-1);

while(R<Q[i].r) R++, add(R);

while(R>Q[i].r) del(R), R--;

ans[Q[i].id] = Ans;

}

rep(i,1,m) printf("%lld\n",ans[i]);

return 0;

}

4.

Chika and Friendly Pairs

问区间里有多少对i,j满足i<j,同时a[i]-a[j]的绝对值小于等于k;

由于 n nn 和 m mm 的范围比较小,可以考虑使用莫队分块算法,在加入和删除的地方使用树状数组统计答案即可。

代码:

#include <bits/stdc++.h>

#define mem(a,b) memset(a,b,sizeof a);

#define rep(i,a,b) for(int i = a; i <= b; i++)

#define per(i,a,b) for(int i = a; i >= b; i--)

#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)

typedef long long ll;

typedef double db;

const int N = 27000+100;

const db EPS = 1e-9;

using namespace std;

void dbg() {cout << "\n";}

template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ‘ ‘; dbg(x...);}

#define logs(x...) {cout << #x << " -> "; dbg(x);}

int n,m,k,a[N],b[3*N],tot,L,R,pos[N],now[N][3];

struct Node{

int l,r,id;

bool operator < (Node xx) const {

if(pos[l] == pos[xx.l]) return r < xx.r;

else return pos[l] < pos[xx.l];

}

}q[N];

ll c[3*N],ans[N],Ans;

inline int lowbit(int x) {return x&(~x+1);}

inline void update(int x,ll v) {for(;x<=tot;x+=lowbit(x)) c[x]+=v;}

inline ll ask(int x){

ll tp = 0;

while(x) tp += c[x], x -= lowbit(x);

return tp;

}

int find(int x){

return lower_bound(b+1,b+1+tot,x)-b;

}

void add(int x){

int p1 = now[x][1], p2 = now[x][2];

Ans += ask(p1)-ask(p2);

update(now[x][0],1);

}

void del(int x){

update(now[x][0],-1);

int p1 = now[x][1], p2 = now[x][2];

Ans -= ask(p1)-ask(p2);

}

int main()

{

L = 1, R = 0;

scanf("%d%d%d",&n,&m,&k);

int sz = sqrt(n);

rep(i,1,n){

scanf("%d",&a[i]);

b[++tot] = a[i]; b[++tot] = a[i]+k; b[++tot] = a[i]-k-1;

pos[i] = i/sz;

}

sort(b+1,b+1+tot);

tot = unique(b+1,b+1+tot)-b-1;

rep(i,1,n){

now[i][0] = find(a[i]);

now[i][1] = find(a[i]+k);

now[i][2] = find(a[i]-k-1);

}

rep(i,1,m){

scanf("%d%d",&q[i].l,&q[i].r);

q[i].id = i;

}

sort(q+1,q+1+m);

rep(i,1,m){

while(L < q[i].l){

del(L);

L++;

}

while(L > q[i].l){

L--;

add(L);

}

while(R < q[i].r){

R++;

add(R);

}

while(R > q[i].r){

del(R);

R--;

}

ans[q[i].id] = Ans;

}

rep(i,1,m) printf("%lld\n",ans[i]);

return 0;

}

5莫队求组合数前缀和

Harvest of Apples

求C(n,0)+C(n,1)+C(n,2)+.....+C(n,m);

设S(n,m)=C(n,0)+C(n,1)+C(n,2)+.....+C(n,m);

第一个式子易得,第二个式子:杨辉三角的c n,m=c(n-1,m)+c(n-1,m-1),利用这个我们来推出s(n,m)就有上面那样公式

那么就是这一行等于上一行的都用了2次,只有第最后一个用了一次

所以减去c(n-1,m)


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

#include<iostream>

#include<stdio.h>

#include<cmath>

#include<algorithm>

using namespace std;

const int mod=1e9+7;

#define ll long long

const int maxn=1e5+7;

ll jiecheng[maxn],inv[maxn];

ll ans[maxn];

int block;

ll qsm(ll a,ll b)

{

    ll ans=1;

    while(b){

        if(b&1)

            ans=ans*a%mod;

        a=a*a%mod;

        b>>=1;

    }

    return ans;

}

void init()

{

    jiecheng[1] = 1;

    for(int i = 2; i < maxn; i++)

        jiecheng[i] = jiecheng[i-1] * i % mod;

    for(int i = 1; i < maxn; i++)

        inv[i] = qsm(jiecheng[i], mod-2);

}

struct node{

    int l,r;

    int i;

}modui[maxn];

bool cmp(node a,node b)

{

    if(a.l/block==b.l/block)

        return a.r<b.r;

    return a.l<b.l;

}

ll C(ll n,ll m)

{

    

    if(m == 0 || m == n) return 1;

    ll ans=1;

    ans=(jiecheng[n]*inv[m])%mod*inv[n-m];

    ans=ans%mod;

    return ans;

}

int main()

{

    init();

    block = sqrt(maxn);

    int t;

    scanf("%d",&t);

    for(int i=0;i<t;i++)

    {

        scanf("%d%d",&modui[i].l,&modui[i].r);

        modui[i].i=i;

    }

    sort(modui,modui+t,cmp);

    int l=1,r=0;

    int sum=1;

    for(int i = 0; i < t; i++)

    {

        while(l < modui[i].l) sum = (2 * sum - C(l++, r) + mod) % mod;

        while(l > modui[i].l) sum = ((sum + C(--l, r))*inv[2]) % mod;

        while(r < modui[i].r) sum = (sum + C(l, ++r)) % mod;

        while(r > modui[i].r) sum = (sum - C(l, r--) + mod) % mod;

        ans[modui[i].i] = sum;

    }

    for(int i=0;i<t;i++)

    {

        printf("%lld\n",ans[i]);

    }

    

    return 0;

}

~~~待修改莫队1. Machine Learning
思路: 这个问题唯一的操作难点在于 mex mexmex 函数的求取,其实我们可以像求取 SG SGSG 函数的 mex mexmex 一样,直接暴力求取即可。然后其余部分就是常规的带修改莫队的操作了。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
typedef double db;
const int N = 2*1e5+100;
const int M = 1e5+100;
const db EPS = 1e-9;
using namespace std;

int n,qq,a[N],b[N],tot,Qnum,Cnum,pos[N],ans[N],L,R,T,flag[N],vis[N];
struct Query{
	int l,r,id,t;
	bool operator < (Query xx) const {
		if(pos[l] != pos[xx.l]) return pos[l] < pos[xx.l];
		else if(pos[r] != pos[xx.r]) return pos[r] < pos[xx.r];
		else return t < xx.t;
	}
}q[M];
struct Change{
	int pos,val;
}C[M];

int find(int x){
	return lower_bound(b+1,b+1+tot,x)-b;
}

void add(int x){
	if(flag[a[x]]!=0) vis[flag[a[x]]]--;
	flag[a[x]]++; vis[flag[a[x]]]++;
}

void del(int x){
	vis[flag[a[x]]]--; flag[a[x]]--;
	if(flag[a[x]] != 0) vis[flag[a[x]]]++;
}

void Work(int x,int i){
	if(C[x].pos >= q[i].l && C[x].pos <= q[i].r){
		vis[flag[a[C[x].pos]]]--; flag[a[C[x].pos]]--;
		if(flag[a[C[x].pos]] != 0) vis[flag[a[C[x].pos]]]++;
		if(flag[C[x].val] != 0) vis[flag[C[x].val]]--;
		flag[C[x].val]++; vis[flag[C[x].val]]++;
	}
	swap(a[C[x].pos],C[x].val);
}

int solve(){
	rep(i,0,n)
		if(!vis[i]) return i;
}

int main()
{
	scanf("%d%d",&n,&qq);
	rep(i,1,n){
		scanf("%d",&a[i]);
		b[++tot] = a[i];
	}
	rep(i,1,qq){
		int op,l,r; scanf("%d%d%d",&op,&l,&r);
		if(op == 1) Qnum++, q[Qnum] = {l,r,Qnum,Cnum};
		else C[++Cnum] = {l,r}, b[++tot] = r;
	}
	sort(b+1,b+1+tot);
	tot = unique(b+1,b+1+tot)-b-1;
	int sz = pow(n,0.66666666666666);
	rep(i,1,n) pos[i] = i/sz;
	sort(q+1,q+1+Qnum);
	L = 1, R = 0, T = 0;
	vis[0] = 1;
	rep(i,1,n) a[i] = find(a[i]);
	rep(i,1,Cnum) C[i].val = find(C[i].val);
	rep(i,1,Qnum){
		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--);
		while(T < q[i].t) Work(++T,i);
		while(T > q[i].t) Work(T--,i);
		ans[q[i].id] = solve();
	}
	rep(i,1,Qnum) printf("%d\n",ans[i]);
	return 0;
}

  

 

#include <bits/stdc++.h>#define rep(i,a,b) for(int i = a; i <= b; i++)typedef long long ll;const int N = 2*1e5+100;using namespace std;
int a[N],pos[N],n,m,L,R;ll ans[N][2],flag[N],Ans;struct Node{int l,r,id;bool operator < (Node xx) const{if(pos[l] == pos[xx.l]) return r < xx.r;else return pos[l] < pos[xx.l];}}Q[N];
ll gcd(ll a,ll b) {return b == 0 ? a:gcd(b,a%b);}
void add(int x){Ans += flag[a[x]];flag[a[x]]++;}
void del(int x){flag[a[x]]--;Ans -= flag[a[x]];}
int main(){L = 1, R = 0;scanf("%d%d",&n,&m);int sz = sqrt(n);rep(i,1,n){scanf("%d",&a[i]);pos[i] = i/sz;}rep(i,1,m){scanf("%d%d",&Q[i].l,&Q[i].r);Q[i].id = i;}sort(Q+1,Q+1+m);rep(i,1,m){while(L < Q[i].l) del(L),L++;
while(L > Q[i].l) L--, add(L);while(R < Q[i].r) R++, add(R);while(R > Q[i].r) del(R), R--;
ll len = Q[i].r-Q[i].l+1;ll tp = len*(len-1ll)/(ll)2;ll g = gcd(Ans,tp);ans[Q[i].id][0] = Ans/g;ans[Q[i].id][1] = tp/g;}rep(i,1,m) printf("%lld/%lld\n",ans[i][0],ans[i][1]);return 0;}————————————————版权声明:本文为CSDN博主「Gene_INNOCENT」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_41552508/article/details/100556943

原文地址:https://www.cnblogs.com/hgangang/p/11618835.html

时间: 2024-08-30 15:46:57

莫队专题的相关文章

专题训练之莫队算法

推荐博客/专栏:https://blog.csdn.net/xianhaoming/article/details/52201761莫队算法讲解(含树上莫队) https://blog.csdn.net/hzj1054689699/article/details/51866615莫队算法 https://zhuanlan.zhihu.com/p/25017840莫队算法 例题及讲解:(BZOJ2038)https://www.luogu.org/problemnew/show/P1494 讲解:

(莫队算法)CodeForces - 617E XOR and Favorite Number

题意: 长度为n的数列,m次询问,还有一个k.每次询问询问询问从数列的L到R内有多少个连续子序列异或起来等于k. 分析: 因为事先知道这题可以用莫队写,就正好用这题练习莫队. 预处理每个前缀异或和. 然后莫队按分块排序后,不断更新,用一个数组cnt[]记录当前L到R前缀和的数量. R向右拉,新增的数量就是cnt[pre^k],pre表示当前这个R位置的前缀异或和,然后更新一下cnt. 其他的也类似. 算是一个比较好的入门题. 代码: 1 #include <cstdio> 2 #include

莫队算法

Beautiful Girl 题意 给定一个长度为 n 的序列 a[1], a[2], ..., a[n] . m 组询问 (l, r, K) , 求区间 [l, r] 去除重复的数之后的第 K 小. n, m <= 100000 . 分析 莫队算法 + 值域分块. 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include &

BZOJ4241 历史研究 莫队算法 堆

欢迎访问~原文出处--博客园-zhouzhendong&AK 去博客园看该题解 题目 Description IOI国历史研究的第一人--JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. 日记中记录了连续N天发生的时间,大约每天发生一件. 事件有种类之分.第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大. JOI教授决定用如下的方法分析这些日记: 1.

CodeForces - 86D 莫队算法

http://codeforces.com/problemset/problem/86/D 莫队算法就是调整查询的顺序,然后暴力求解. 每回可以通过现有区间解ans(l,r)得到区间(l+1,r),(l-1,r),(l,r+1),(l,r-1)的区间解. 调整方式http://blog.csdn.net/bossup/article/details/39236275 这题比那个还要简单,查询的是K^2*Z,很清楚就是莫队算法,然而做的时候没有学过,回来补题补到 关键是我一直没明白为什么重载小于号

codeforces 617 E. XOR and Favorite Number(莫队算法)

题目链接:http://codeforces.com/problemset/problem/617/E 题目: 给你a1 a2 a3 ··· an 个数,m次询问:在[L, R] 里面又多少中 [l, r] 使得 al xor al+1 xor ··· ar 为 k. 题解: 本题只有区间查询没有区间修改,而且数据量不大(10w),所以可以用离线的方法解决. 使用莫队算法来解决,就需要O(1)的修改[L, R+1] .[L, R-1].[L+1, R].[L-1, R]. 详细的莫队可以百度学一

洛谷 P2056 采花 - 莫队算法

萧芸斓是 Z国的公主,平时的一大爱好是采花. 今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花.花园足够大,容纳了 n 朵花,花有 c 种颜色(用整数 1-c 表示) ,且花是排成一排的,以便于公主采花. 公主每次采花后会统计采到的花的颜色数, 颜色数越多她会越高兴! 同时, 她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵.为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花. 由于时间关系,公主只能走过花园连续的一段进行采

hdu NPY and girls 莫队+逆元

NPY and girls Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description NPY's girlfriend blew him out!His honey doesn't love him any more!However, he has so many girlfriend candidates.Because there are to

洛谷 P3674 小清新人渣的本愿 [莫队 bitset]

传送门 题意: 给你一个序列a,长度为n,有Q次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3 题面太强啦!!! 感觉就是莫队,想了一下分块不好搞更坚定了莫队的信念 $a-b=x$,$a=x+b$,放在权值数组上就是b右移x位,$bitset$大法好 加法同理 乘法,总共就$\sqrt{N}$个约数.... #include <iostream> #incl