• [NOI Online #2 提高组]子序列问题


    description:

    题目已经说得很清楚了

    solution:

    我们考虑记(F_i=sum_{k=1}^if(k,i)^2)
    考虑(F_i)如何由(F_{i-1})递推过来
    我们用(pre_{a_i})表示(a_i)这个值上一次出现的位置(从未出现过则记为0)(下面简记为(j)
    根据定义,
    (F_i=sum_{k=1}^if(k,i)^2)
    (F_{i-1}=sum_{k=1}^{i-1}f(k,i-1)^2)
    同时对于(forall kle j)(f_{k,i}==f_{k,i-1})
    对于(forall k> j)(f_{k,i}==f_{k,i-1}+1)其中(f_{i,i-1})定义为(0)
    因此(F_i-F_{i-1}=sum_{k=j+1}^i((f_{k,i-1}+1)^2-f_{k,i-1}^2))
    稍微推下柿子可得(原式=(i-j)+2sum_{k=j+1}^{i-1}f_{k,i-1})
    然后就可以发现这就是一个区间加&区间求和的东西,直接上线段树来维护就可以了
    最后答案就是(ans=sum_{i=1}^nF_i)

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+5,mod=1e9+7;
    int n,a[N],b[N],pre[N],f[N];
    inline int read()
    {
    	int s=0,w=1; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
    	for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
    	return s*w;
    }
    inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    struct SGT
    {
    	int tag[N<<2],s[N<<2];
    	#define lc rt<<1
    	#define rc rt<<1|1
    	inline void up(int rt){s[rt]=add(s[lc],s[rc]);}
    	inline void down(int rt,int l,int r)
    	{
    		int &tg=tag[rt];
    		if(!tg)return;
    		int mid=(l+r)>>1,lenl=mid-l+1,lenr=r-mid;
    		s[lc]=add(s[lc],1ll*lenl*tg%mod),s[rc]=add(s[rc],1ll*lenr*tg%mod);
    		tag[lc]=add(tag[lc],tg),tag[rc]=add(tag[rc],tg);
    		tg=0;
    	}
    	void upd(int rt,int ll,int rr,int l=1,int r=n)
    	{
    		if(ll<=l&&r<=rr){s[rt]=add(s[rt],r-l+1),++tag[rt];return;}
    		down(rt,l,r);
    		int mid=(l+r)>>1;
    		if(ll<=mid)upd(lc,ll,rr,l,mid);
    		if(mid<rr)upd(rc,ll,rr,mid+1,r);
    		up(rt);
    	}
    	int query(int rt,int ll,int rr,int l=1,int r=n)
    	{
    		if(ll<=l&&r<=rr)return s[rt];
    		down(rt,l,r);
    		int mid=(l+r)>>1,anss=0;
    		if(ll<=mid)anss=add(anss,query(lc,ll,rr,l,mid));
    		if(mid<rr)anss=add(anss,query(rc,ll,rr,mid+1,r));
    		up(rt);return anss;
    	}
    	#undef lc
    	#undef rc
    }T;
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)a[i]=read(),b[i]=a[i];
    	sort(b+1,b+n+1);
    	int tot=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n;++i)
    		a[i]=lower_bound(b+1,b+tot+1,a[i])-b;//离散化
    	for(int i=1;i<=n;++i)
    	{
    		int j=pre[a[i]];
    		f[i]=add(f[i-1],i-j);
    		if(j+1<=i-1)f[i]=add(f[i],2*T.query(1,j+1,i-1)%mod);
    		T.upd(1,j+1,i);pre[a[i]]=i;
    	}
    	int ans=0;
    	for(int i=1;i<=n;++i)ans=add(ans,f[i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    vue--三种组件中之间的传值
    数学log的基本知识
    通俗易懂理解——dijkstra算法求最短路径
    数据结构--Dijkstra算法最清楚的讲解
    explorer.exe
    经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)
    WPF路由事件二:路由事件的三种策略
    luogu P1979 华容道
    4.Linux查看文件大小的几种方法
    Pairing heap
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13843245.html
Copyright © 2020-2023  润新知