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;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    HDU 1124 Factorial
    hdu 1690 Bus System
    hdu 1113 Word Amalgamation
    POJ 2482 Stars in Your Window
    hdu 1385 ZOJ 1456 Minimum Transport Cost(经典floyd)
    hdu 1907 John
    VMware 虚拟机 安装 UBuntu 9.10 命令模式转换成窗口模试
    #pragma CODE_SEG __NEAR_SEG NON_BANKED详解
    Ubuntu 下Hadoop 伪分布式 hadoop0.20.2.tar.gz 的安装
    文件拷贝代码以及疑问
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3587.html
Copyright © 2011-2022 走看看