莫队算法习题

1. XOR and Favorite Number

注意:

  1. 前缀和的缘故,q[i].l 需要减减。
  2. 因为pre[l - 1] ^ pre[r] = k,所以pre[r] ^ k = pre[l - 1]
  3. (a[1] ^ a[2] ^ … ^ a[10]) ^ (a[1] ^ a[2] ^ … ^ a[5]) = a[6] ^ a[7] ^ … ^ a[10]
/*
 * Author:  Chen_zhuozhuo
 * Created Time:  2020/3/24 10:07:59
 * File Name: b.cpp
 */
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <time.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const ll maxll = -1u>>1;
const ll inf = 0x3f3f3f3f;
const ll maxn = 2e6 + 10;
ll pos[maxn],vis[maxn],Ans[maxn],pre[maxn];
ll n,m,k,ans;
 
struct Query{
    ll l, r, id;
}Q[maxn];
 
bool cmp(Query a, Query b){
    if(pos[a.l] == pos[b.l])
        return a.r < b.r;
    else
        return pos[a.l] < pos[b.l];
}
 
void add(ll pos){
    ans += vis[pre[pos]^k];
    vis[pre[pos]] ++;
}
 
void del(ll pos){
    vis[pre[pos]] --;
    ans -= vis[pre[pos]^k];
}
 
int main() {
    cin>>n>>m>>k;
    ll sz = sqrt(n);
    for(ll i=1;i<=n;i++){
        cin>>pre[i];
        pre[i] = pre[i] ^ pre[i - 1];
        pos[i] = i / sz;
    }
    for(ll i=1;i<=m;i++){
        cin>>Q[i].l>>Q[i].r;
        Q[i].l --;
        Q[i].id = i;
    }
    sort(Q+1, Q+1+m, cmp);
    ll L=1, R=0;
    for(ll 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 --);
        Ans[Q[i].id] = ans;
    }
    for(ll i=1;i<=m;i++){
        cout<<Ans[i]<<endl;
    }
    return 0;
}
/*
6 2 3
1 2 1 1 0 3
1 6
3 5
 
7
0
*/

2. 小Z的袜子

注意:

  1. 注释的重载运算符排序写反了,后边两端注释是对的。
  2. 数学上边稍微化简一下,a[1](a[1]-1) + a[2](a[2]-1)+…+a[n]*(a[n]-1) = a[1]平方+a[2]平方 + …+ a[n]平方 - (a[1] + a[2] + … + a[n]),且a[1] + a[2] +…+a[n] == len == R - L + 1
/*
 * Author:  Chen_zhuozhuo
 * Created Time:  2020/3/24 10:50:12
 * File Name: a.cpp
 */
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 5e4 + 10;
int pos[maxn],a[maxn];
ll AnsFZ[maxn],vis[maxn],AnsFM[maxn];
ll n,m,temp;
int L = 1, R = 0;

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

struct Query{
    int l, r, id;
    //bool operator < (const Query b)const {
        //if(pos[l] == pos[b.l])
            //return pos[l] < pos[b.l];
        //else
            //return r < b.r;
    //}
}q[maxn];

bool cmp(Query a, Query b){
    if(pos[a.l] == pos[b.l])
        return a.r < b.r;
    else
        return pos[a.l] < pos[b.l];
}

inline int getlen(Query a){
    return a.r - a.l + 1;
}

void add(int x)
{
    temp -= vis[x]*vis[x];
    vis[x]++;
    temp += vis[x]*vis[x];
}
 
void del(int x)
{
    temp -= vis[x]*vis[x];
    vis[x]--;
    temp += vis[x]*vis[x];
}

//void add(int p){
    //int k = a[p];
    //temp -= vis[k] * vis[k];
    //vis[k] ++;
    //temp += vis[k] * vis[k]; 
//}
//
//void del(int p){
    //int k = a[p];
    //temp -= vis[k] * vis[k];
    //vis[k] --;
    //temp += vis[k] * vis[k];
//}

int main() {
   scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int sz = sqrt(n);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id = i;
            pos[i] = i / sz;
        }
        sort(q + 1, q + 1 + m, cmp);
        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 --);
            while(R < q[i].r) add(a[++R]);
            while(R > q[i].r) del(a[R--]);
            while(L < q[i].l) del(a[L++]);
            while(L > q[i].l) add(a[--L]);
            int len = getlen(q[i]);
            ll fenzi = temp - len;
            ll fenmu = (ll)len * (len - 1);
            ll gcd = GCD(fenzi,fenmu);
            AnsFZ[q[i].id] = fenzi / gcd;
            AnsFM[q[i].id] = fenmu / gcd;
            if(!fenzi)
                AnsFM[q[i].id] = 1;
        }
    
        for(int i=1;i<=m;i++)
            printf("%lld/%lld\n",AnsFZ[i],AnsFM[i]);
    return 0;
}

/*
Sample Input
6 4
1 2 3 3 3 2
2 6
1 3
3 5
1 6
Sample Output
2/5
0/1
1/1
4/15 
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值