题解 P5072 【[Ynoi2015] 盼君勿忘】
简化题面
珂朵莉给了你一个序列,每次查询一个区间\([l,r]\)中所有子序列分别去重后的和\(\bmod p\)。
\(1 \le n,m,a_i \le 10^5,1\le p \le 10^9,1\le l \le r \le n\)
解题思路
最简单的一道\(Ynoi\)?
考虑如果一个数\(x\)在区间\([l,r]\)出现了\(k\)次,那么显然会出现在长度为\(r-l+1-k\)的所有集合内,那么产生贡献的总集合个数为\(2^{r-l+1}-2^{r-l+1-k}\)
考虑如何统计区间内每个数出现的个数,显然\(HH\)的项链啊= =
直接暴力上莫队,用\(stl\)自带的\(unordered set\)来维护
考虑维护每个数的个数\(cnt\),维护个数为\(x\)个的数的和\(sum\)。
在转移区间的时候如果是添加贡献,那么先将原来这个位置的数的个数对\(sum\)的贡献减去,如果为\(0\)了就删掉,然后增加\(cnt\)后的\(sum\)添加到\(set\)内,减的话同理,具体实现看代码。
如果加上个快速幂时间复杂度显然为\(O(n\sqrt{m} logn)\)会\(T\)掉
直接上光速幂即可,然后如果自己闲的没事的话也可以拿个链表之类的数据结构维护一下个数也行,普通莫队排序还是会\(T\),这里代码用的是奇偶优化后的莫队排序
\(\mathcal{Code}\)
// Author: Ame__
#include<bits/stdc++.h>
#define _ 0
#define qwq double
#define AME__DEBUG
#define LL long long
#define bomb exit(0)
#define LOG(FMT...) fprintf(stderr , FMT)
#define TOWA(FMT...) fprintf(stdout , FMT)
using namespace std;
/*Grievous Lady*/
const int BUF_SIZE = 1 << 12;
char buf[BUF_SIZE] , *buf_s = buf , *buf_t = buf + 1;
#define PTR_NEXT() \
{ \
buf_s ++; \
if(buf_s == buf_t) \
{ \
buf_s = buf; \
buf_t = buf + fread(buf , 1 , BUF_SIZE , stdin); \
} \
}
#define mians(_s_) \
{ \
while(!isgraph(*buf_s)) PTR_NEXT();\
char register *_ptr_ = (_s_); \
while(isgraph(*buf_s) || *buf_s == '-') \
{ \
*(_ptr_ ++) = *buf_s; \
PTR_NEXT(); \
} \
(*_ptr_) = '\0'; \
}
template <typename _n_> void mian(_n_ & _x_){
while(*buf_s != '-' && !isdigit(*buf_s)) PTR_NEXT();
bool register _nega_ = false; if(*buf_s == '-'){ _nega_ = true; PTR_NEXT(); }
_x_ = 0; while(isdigit(*buf_s)){ _x_ = _x_ * 10 + *buf_s - '0'; PTR_NEXT(); } if(_nega_) _x_ = -_x_;
}
const int kato = 1e5 + 10;
template <typename _n_> bool cmax(_n_ &a , const _n_ &b){ return a < b ? a = b , 1 : 0; }
template <typename _n_> bool cmin(_n_ &a , const _n_ &b){ return a > b ? a = b , 1 : 0; }
int n , m , bol;
LL a[kato] , cnt[kato] , sum[kato] , ans[kato];
unordered_set<int> deco;
class quick_quick_pow{
private:
LL res1[kato] , res2[kato]; int N;
public:
inline void get_ans(int mod){
res1[0] = res2[0] = 1;
for(int i = 1;i <= bol;i ++) res1[i] = 1LL * res1[i - 1] * 2 % mod;
for(int i = 1;i <= bol;i ++) res2[i] = 1LL * res2[i - 1] * res1[bol] % mod;
}
inline LL qaq(int x , int mod){ return 1LL * res1[x % bol] * res2[x / bol] % mod; }
}towa;
struct node{
int l , r , id , mod;
friend bool operator <(const node &a , const node &b){
return (a.l / bol ^ b.l / bol) ? a.l / bol < b.l / bol : (a.l / bol & 1) ? a.r < b.r : a.r > b.r;
}
}e[kato];
inline void add(int x){
if(cnt[a[x]]){
sum[cnt[a[x]]] -= a[x];
if(!sum[cnt[a[x]]]) deco.erase(cnt[a[x]]);
}
cnt[a[x]] ++;
if(!sum[cnt[a[x]]]) deco.insert(cnt[a[x]]);
sum[cnt[a[x]]] += a[x];
}
inline void del(int x){
sum[cnt[a[x]]] -= a[x];
if(!sum[cnt[a[x]]]) deco.erase(cnt[a[x]]);
cnt[a[x]] --;
if(cnt[a[x]]){
if(!sum[cnt[a[x]]]) deco.insert(cnt[a[x]]);
sum[cnt[a[x]]] += a[x];
}
}
inline int get_sum(int l , int r , int mod){
LL res = 0 , tot = towa.qaq(r - l + 1 , mod);
for(auto it = deco.begin(); it != deco.end(); it ++) res = (res + sum[*it] * (tot - towa.qaq(r - l + 1 - *it , mod) + mod) % mod) % mod;
return res % mod;
}
inline int Ame_(){
#ifdef AME__
freopen(".in" , "r" , stdin); freopen(".out" , "w" , stdout); int nol_cl = clock();
#endif
mian(n) , mian(m); bol = sqrt(m);
for(int i = 1;i <= n;i ++) mian(a[i]);
for(int i = 1;i <= m;i ++){
mian(e[i].l) , mian(e[i].r) , mian(e[i].mod);
e[i].id = i;
}
sort(e + 1 , e + 1 + m);
int l = e[1].l , r = l - 1;
for(int i = 1;i <= m;i ++){
while(l > e[i].l) add(-- l);
while(r < e[i].r) add(++ r);
while(l < e[i].l) del(l ++);
while(r > e[i].r) del(r --);
towa.get_ans(e[i].mod);
ans[e[i].id] = get_sum(e[i].l , e[i].r , e[i].mod);
}
for(int i = 1;i <= m;i ++) TOWA("%lld\n" , ans[i]);
#ifdef AME__TIME
LOG("Time: %dms\n", int((clock() - nol_cl) / (qwq)CLOCKS_PER_SEC * 1000));
#endif
return ~~(0^_^0); /*さようならプログラム*/
}
int Ame__ = Ame_();
int main(){;}
/*
4 2
1 7
6 8
7 10
9 13
*/
呐,这份感情,什么时候可以传达呢