• Codechef SEAARC Sereja and Arcs (分块)


    我现在真的什么都不会了呢......

    题目链接: https://www.codechef.com/problems/SEAARC

    好吧,这题其实考察的是枚举的功力……

    题目要求的是(ABAB)的数量,这个不太好求,但是不同颜色区间对的总数和(AABB,ABBA)的都比较好求

    补集转化,求(ans0,ans1,ans2), 分别表示总数、(AABB)(ABBA)的数量

    (ans0)很好算

    (ans1), 枚举(B)的左端点

    (ans2), 分块讨论

    (A,B)都是小颜色(该颜色块的数量小于阈值),则枚举(A)的左右端点,变成二维数点

    (A)是大颜色(B)是小颜色,则枚举(A)的种类,然后枚举(B)的种类和左右端点,推一下式子发现可以维护前缀和省去枚举左端点

    (B)是大颜色,同理枚举(B)的种类然后枚举(A)的种类和左右端点,同样省去枚举左端点

    从昨天下午做到今天上午。。

    理论最优时间复杂度(O(nsqrt{nlog n}))

    代码

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cassert>
    #include<vector>
    #include<cmath>
    #define llong long long
    using namespace std;
    
    const int N = 1e5;
    const int P = 1e9+7;
    const llong INV2 = 5e8+4;
    int nxt[N+3];
    int lstpos[N+3];
    int a[N+3];
    int num[N+3];
    int cnum[N+3];
    llong tmp0[N+3],tmp1[N+3],tmp2[N+3];
    vector<int> clrpos[N+3];
    int n,m,B;
    llong ans1,ans2a,ans2b,ans2c,ans0,ans;
    
    llong C2(llong x) {return x*(x-1ll)/2ll%P;}
    llong update(llong &x,llong y) {x = (x+y)%P;}
    
    struct BITree
    {
    	llong tr[N+3]; int siz;
    	void addval(int lrb,llong val)
    	{
    		while(lrb<=siz)
    		{
    			update(tr[lrb],val);
    			lrb += (lrb&(-lrb));
    		}
    	}
    	llong querysum(llong rb)
    	{
    		llong ret = 0ll;
    		while(rb)
    		{
    			update(ret,tr[rb]);
    			rb -= (rb&(-rb));
    		}
    		return ret;
    	}
    	void clear()
    	{
    		for(int i=0; i<=siz; i++) tr[i] = 0ll;
    	}
    } bit1,bit2;
    
    void getans0() //ans0=ËùÓÐÑÕÉ«C(num,2)Á½Á½³Ë»ýÖ®ºÍ ²»ËãAAAA 
    {
    	llong cur = 0ll;
    	for(int i=1; i<=m; i++)
    	{
    		llong tmp = C2(num[i]);
    		update(ans0,cur*tmp%P);
    		update(cur,tmp);
    	}
    }
    
    void getans1() //²»ËãAAAA 
    {
    	llong tmp = 0ll; //µ±Ç°×ܹ²Í¬É«Çø¼äµÄ¸öÊý 
    	for(int i=1; i<=n; i++)
    	{
    		update(ans1,(tmp-C2(cnum[a[i]]))*(num[a[i]]-cnum[a[i]]-1)); //ÕâÖÖÑÕÉ«×ܸöÊý¼õÕâ֮ǰµÄ¸öÊý-1£¬µÈÓÚÕâÖ®ºóµÄ¸öÊý£¬³ËÒÔÇ°ÃæµÄÒìÉ«¸öÊý 
    		update(tmp,(llong)cnum[a[i]]); //ÕâÖÖÑÕɫ֮ǰµÄ¸öÊý 
    		cnum[a[i]]++;
    	}
    }
    
    void getans2a() //small-small ²»ËãAAAA 
    {
    	bit1.siz = n; bit1.clear(); llong cur = 0ll;
    	for(int i=1; i<=n; i++) //ö¾ÙÓҶ˵ã 
    	{
    		if(num[a[i]]<=B)
    		{
    			int tnum = 0;
    			for(int j=nxt[i]; j; j=nxt[j])
    			{
    				llong tmp = cur-bit1.querysum(j)-C2(tnum)+P+P; //>jµÄ×ó¶ËµãµÄ¸öÊý=×ܸöÊý¼õ<=jµÄ¸öÊý£¬È¥µôͬɫµÄ¸öÊý(²»ËãiºÍj)
    				update(ans2a,tmp);
    				tnum++; //ͬɫ¸öÊý 
    			}
    			for(int j=nxt[i]; j; j=nxt[j]) //ÓÉÓÚÊÇÓҶ˵ãСÓÚj£¬ÏÈÐ޸ĺó²éѯ 
    			{
    				cur++; //Ä¿Ç°Çø¼ä×ܸöÊý,¼´bit1.querysum(i) 
    				bit1.addval(j,1);
    			}
    		}
    	}
    }
    
    void getans2b() //large-small
    {
    	for(int i=1; i<=m; i++) //ö¾ÙAÖÖÀà
    	{
    		if(num[i]>B) 
    		{
    			tmp1[0] = 0ll; for(int j=1; j<=n; j++) tmp1[j] = tmp1[j-1]+(a[j]==i?1:0);
    			for(int j=1; j<=m; j++)  //ö¾ÙBÖÖÀà 
    			{
    				if(num[j]<=B)
    				{
    					llong cur = 0ll;
    					for(int k=0; k<clrpos[j].size(); k++)
    					{
    						int rb = clrpos[j][k];
    						llong tmp = (num[i]-tmp1[rb])*cur%P;
    						update(ans2b,tmp); 
    						update(cur,tmp1[rb]); //lb²»¿ÉµÈÓÚrb, ËùÒÔÏȸüÐÂans2bÔÙ¸üÐÂcur 
    					}
    				}
    			}
    		}
    	}
    }
    
    void getans2c() //large-large or small-large ²»ËãAAAA 
    {
    	for(int i=1; i<=m; i++) //ö¾ÙBµÄÖÖÀà 
    	{
    		if(num[i]>B)
    		{
    			tmp1[0] = 0; for(int j=1; j<=n; j++) tmp1[j] = tmp1[j-1]+(a[j]==i?1:0);
    			for(int j=1; j<=m; j++) //ö¾ÙAµÄÖÖÀà 
    			{
    				if(i==j) continue;
    				llong cur1 = 0ll,cur2 = 0ll;
    				for(int k=0; k<clrpos[j].size(); k++) //ö¾Ùra
    				{
    					//¸üÐÂans2c 
    					int ra = clrpos[j][k];
    					llong tmp = tmp1[ra]*tmp1[ra]%P*k%P;
    					update(ans2c,tmp);
    					tmp = tmp1[ra]*(-2ll*cur1-k)%P+P;
    					update(ans2c,tmp);
    					tmp = cur2+cur1+P;
    					update(ans2c,tmp);
    					//¸üÐÂcur1,cur2 
    					update(cur2,tmp1[ra]*tmp1[ra]);
    					update(cur1,tmp1[ra]);
    				}
    			}
    		}
    	}
    	ans2c = ans2c*INV2%P;
    }
    
    int main()
    {
    	scanf("%d",&n); B = sqrt(n)/2;
    	for(int i=1; i<=n; i++) scanf("%d",&a[i]),num[a[i]]++,m = max(m,a[i]),clrpos[a[i]].push_back(i);
    	for(int i=1; i<=n; i++)
    	{
    		nxt[i] = lstpos[a[i]];
    		lstpos[a[i]] = i;
    	}
    	getans0();
    	getans1();
    	getans2a();
    	getans2b();
    	getans2c();
    	ans = ((ans0-ans1-ans2a-ans2b-ans2c)%P+P)%P;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Baum Welch估计HMM参数实例
    SVM 为什么要从原始问题变为对偶问题来求解
    Baum-Welch算法(EM算法)对HMM模型的训练
    LR采用的Sigmoid函数与最大熵(ME) 的关系
    01背包的常数优化的一点解释
    训练中文词向量
    TensorFlow L2正则化
    TensorFlow batch normalize的使用
    听说你的模型损失是NaN
    编译TensorFlow CPU指令集优化版
  • 原文地址:https://www.cnblogs.com/suncongbo/p/11108704.html
Copyright © 2020-2023  润新知