zoukankan      html  css  js  c++  java
  • 【洛谷3587】[POI2015] POD(哈希)

    点此看题面

    • 一个长度为(n)的环,每个点有一个颜色。
    • 要求把这个环断成两条链,满足同种颜色的点全在一条链中。
    • 求方案数以及所有方案中两条链长度差的最小值。
    • (n,kle10^6)

    哈希判断

    先考虑单独某种颜色,设该颜色点数为(c),记(s_i)为前(i)个点中这种颜色的点数。

    假设我们选取了(l,r)两个位置断开,那么(l+1sim r)中这种颜色的点数必须为(0)(c),也就是说(s_r-s_{l}equiv0(mod c)),即(s_lequiv s_r(mod c))

    那么我们只要对于第(i)位把所有颜色各自的(s_i\%c)哈希起来求出(h_i)(在一个位置上只有当前位置对应颜色的(s_i)会发生变化),则能够选取(l,r)两个位置断开当且仅当(h_l=h_r)

    因此把(h_i)相同的点归为一类,方案数容易计算,最小差值双指针搞一下即可。

    代码:(O(nlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Rg register
    #define RI Rg int
    #define Cn const
    #define CI Cn int&
    #define I inline
    #define W while
    #define N 1000000
    using namespace std;
    int n,k,a[N+5],c[N+5],lst[N+5],id[N+5];struct Hash
    {
    	#define ull unsigned long long
    	#define CU Cn ull&
    	ull x,y;I Hash() {x=y=0;}I Hash(CU a) {x=y=a;}I Hash(CU a,CU b):x(a),y(b){}
    	I Hash operator + (Cn Hash& o) Cn {return Hash(x+o.x,y+o.y);} 
    	I Hash operator - (Cn Hash& o) Cn {return Hash(x-o.x,y-o.y);} 
    	I Hash operator * (Cn Hash& o) Cn {return Hash(x*o.x,y*o.y);}
    	I bool operator < (Cn Hash& o) Cn {return x^o.x?x<o.x:y<o.y;}
    	I bool operator == (Cn Hash& o) Cn {return x==o.x&&y==o.y;}
    }h[N+5],pw[N+5],sd(456789001,324682339);
    I bool cmp(CI x,CI y) {return h[x]==h[y]?x<y:h[x]<h[y];}
    int main()
    {
    	RI i,j;for(scanf("%d%d",&n,&k),pw[0]=i=1;i<=k;++i) pw[i]=pw[i-1]*sd;
    	for(i=1;i<=n;++i) scanf("%d",a+i),++c[a[i]],lst[a[i]]=i,id[i]=i;
    	for(i=1;i<=n;++i) h[i]=h[i-1]+pw[a[i]],i==lst[a[i]]&&(h[i]=h[i]-pw[a[i]]*c[a[i]],0);//哈希
    	long long ans=0;RI res=n,p,q,z;for(sort(id+1,id+n+1,cmp),i=1;i<=n;i=j+1)
    	{
    		for(j=i;j^n&&h[id[i]]==h[id[j+1]];++j);ans+=1LL*(j-i+1)*(j-i)/2;//哈希值相同的一段
    		for(p=i+1,q=i;p<=j;++p) {W(2*(id[p]-id[q+1])>=n) ++q;//双指针
    			res=min(res,abs(2*(id[p]-id[q])-n)),p^(q+1)&&(res=min(res,abs(2*(id[p]-id[q+1])-n)));}//取在分界线两侧
    	}return printf("%lld %d
    ",ans,res),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    CentOS中安装Nginx
    SSM框架中Mybatis的分页插件PageHelper分页失效的原因
    linux相关设置
    windows下安装ElasticSearch的Head插件
    git学习
    消息队列介绍和SpringBoot2.x整合RockketMQ、ActiveMQ 9节课
    C# if语句
    C# switch语句
    C# for语句
    C# foreach语句
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3587.html
Copyright © 2011-2022 走看看