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;
    }
    

      

  • 相关阅读:
    在本地连接服务器上的mysql数据库
    js提取字符串中的数值
    下载安装mysql
    git最基础操作二(clone)
    点击页面出现富强、民主
    解决wepacke配置postcss-loader时autoprefixer失效问题
    li之间产生的间隙问题的解决方法
    webpack简单体验
    apply、call和bind
    remote Incorrect username or password ( access token)问题解决
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/10102814.html
Copyright © 2011-2022 走看看