zoukankan      html  css  js  c++  java
  • [Ynoi2015]盼君勿忘

    题目大意:

    给定一个序列,每次查询一个区间([l,r])中所有子序列分别去重后的和(mod p)(每次询问模数不同)。

    解题思路:

    在太阳西斜的这个世界里,置身天上之森。等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去、逐渐消逝的未来。我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘。————世界上最幸福的女孩

    珂朵莉,要永远幸福哦。

    ---

    我们考虑每个数的贡献。即该区间内含有这个数的子序列个数。用补集转化为不含这个数的子序列个数。

    那么,假设这个数在([l,r])内出现了(k)次,则一共有(2^{r-l+1}-2^{r-l+1-k})个子序列**包含**这个数。

    所以,我们莫队,维护所有出现(k)次的不同数的和,然后包含这些数的子序列个数都相同,所以直接用和来计算贡献即可。

    时间复杂度(O(nm)),非常优秀

    考虑根号内分类讨论。

    对于出现次数大于(sqrt n)的数,这种数最多不到(sqrt n)个。

    所以我们莫队,统计出现次数小于等于(sqrt n)的所有出现次数为(i)的和(s_i),然后用一个东西来维护所有出现次数大于(sqrt n)的数。

    这样的话,每次询问的复杂度就是(O(sqrt n))了。

    看上去好像没什么问题,实际上你会发现求2的幂次还有个(log),而且模数会改,不好预处理。

    有一种分块(O(sqrt n))预处理,(O(1))求幂次的方法,具体就是求出(2^0,2^1,2^2,dots,2^{{sqrt n}-1})和(2^{sqrt n},2^{2sqrt n},dots,2^n)(模意义),然后每个幂都分成两部分相乘即可。

    每次询问重新计算一遍即可。

    然后我们考虑用什么东西来维护出现次数大于(sqrt n)的数。我用了unordered_set,理论上是线性的(当然这个理论有多可靠就不知道了)

    这样总时间复杂度(O((n+m)sqrt n)),空间复杂度(O(n))。

    C++ Code:

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<vector>
    #include<unordered_set>
    #ifdef ONLINE_JUDGE
    struct istream{
        char buf[23333333],*s;
        inline istream(){
            buf[fread(s=buf,1,23333330,stdin)]='
    ';
            fclose(stdin);
        }
        inline istream&operator>>(int&d){
            d=0;
            for(;!isdigit(*s);++s);
            while(isdigit(*s))
            d=(d<<3)+(d<<1)+(*s++^'0');
            return*this;
        }
    }cin;
    struct ostream{
        char buf[8000005],*s;
        inline ostream(){s=buf;}
        inline ostream&operator<<(int d){
            if(!d){
                *s++='0';
            }else{
                static int w;
                for(w=1;w<=d;w*=10);
                for(;w/=10;d%=w)*s++=d/w^'0';
            }
            return*this;
        }
        inline ostream&operator<<(const char&c){*s++=c;return*this;}
        inline void flush(){
            fwrite(buf,1,s-buf,stdout);
            s=buf;
        }
        inline~ostream(){flush();}
    }cout;
    #else
    #include<iostream>
    using std::cin;
    using std::cout;
    #endif
    #define siz 317
    #define N 100005
    int n,m,a[N],buc[N],_2[siz+2],__2[siz+2],out[N];
    long long bvc[siz+2];
    std::vector<int>lr;
    std::unordered_set<int>s;
    inline int pow2(int b,const int&md){
    	int ret=1,a=2;
    	for(;b;b>>=1,a=1LL*a*a%md)
    	if(b&1)ret=1LL*ret*a%md;
    	return ret;
    }
    inline int pw2(int m,const int&md){
    	return 1LL*_2[m%siz]*__2[m/siz]%md;
    }
    struct que{
    	int l,r,id,md;
    	inline bool operator<(const que&rhs)const{
    		return(l/siz!=rhs.l/siz)?(l<rhs.l):(r<rhs.r);
    	}
    }q[N];
    inline void add(int pos){
    	const int val=a[pos];
    	if(buc[val]>siz)++buc[val];else
    	if(buc[val]==siz)bvc[buc[val]++]-=lr[val],s.insert(val);else
    	bvc[buc[val]]-=lr[val],bvc[++buc[val]]+=lr[val];
    }
    inline void del(int pos){
    	const int val=a[pos];
    	if(buc[val]>siz+1)--buc[val];else
    	if(buc[val]==siz+1)s.erase(val),bvc[--buc[val]]+=lr[val];else
    	bvc[buc[val]]-=lr[val],bvc[--buc[val]]+=lr[val];
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;lr.push_back(a[i++]))cin>>a[i];
    	std::sort(lr.begin(),lr.end());
    	for(int i=1;i<=n;++i)a[i]=lower_bound(lr.begin(),lr.end(),a[i])-lr.begin();
    	for(int i=1;i<=m;++i)
    	cin>>q[q[i].id=i].l>>q[i].r>>q[i].md;
    	std::sort(q+1,q+m+1);
    	int l=1,r=0;
    	for(int i=1;i<=n;++i)*bvc+=a[i];
    	*_2=*__2=1;
    	for(int i=1;i<=m;++i){
    		while(r<q[i].r)add(++r);
    		while(l>q[i].l)add(--l);
    		while(r>q[i].r)del(r--);
    		while(l<q[i].l)del(l++);
    		const int md=q[i].md,len=r-l+1;
    		for(int j=1;j<siz;++j)
    		_2[j]=2LL*_2[j-1]%md;
    		__2[1]=pow2(siz,md);
    		for(int j=2;j<=siz;++j)
    		__2[j]=__2[1]*1LL*__2[j-1]%md;
    		int&ans=out[q[i].id];
    		const int all=pw2(len,md);
    		for(int j=1;j<=siz;++j)
    		(ans+=1LL*(all-pw2(len-j,md)+md)*bvc[j]%md-md)+=ans>>31&md;
    		for(int j:s){
    			(ans+=1LL*(all-pw2(len-buc[j],md)+md)*lr[j]%md-md)+=ans>>31&md;
    		}
    	}
    	for(int i=1;i<=m;++i)cout<<out[i]<<'
    ';
    	return 0;
    }
    

      

  • 相关阅读:
    Good Bye 2014 B. New Year Permutation(floyd )
    hdu 5147 Sequence II (树状数组 求逆序数)
    POJ 1696 Space Ant (极角排序)
    POJ 2398 Toy Storage (叉积判断点和线段的关系)
    hdu 2897 邂逅明下 (简单巴什博弈)
    poj 1410 Intersection (判断线段与矩形相交 判线段相交)
    HDU 3400 Line belt (三分嵌套)
    Codeforces Round #279 (Div. 2) C. Hacking Cypher (大数取余)
    Codeforces Round #179 (Div. 2) B. Yaroslav and Two Strings (容斥原理)
    hdu 1576 A/B (求逆元)
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/10102814.html
Copyright © 2011-2022 走看看