复读数组
分成 3 种区间算答案:
- 一个块内的区间
- 两个块交界处,长度小于块长的区间
- 长度不小于块长的区间
对于第三种区间,容易发现每个区间的权值一样,只需要算出个数即可.
对于前两种空间,我的思路是:对于一个重复出现的元素,记第一次出现的这个元素贡献权值,然后讨论每一个数会给哪些区间贡献权值即可.
3年OI一场空
不开long long见祖宗
代码:
#include<bits/stdc++.h>
#define LL long long
#define int long long
const int SIZE=200005,Mod=1000000007;
int n,k,Raw[SIZE],A[SIZE],Tot;
int pre[SIZE],nex[SIZE],pos[SIZE];
bool mk[SIZE];
long long Ans=0;
LL Pow(LL B,int P)
{
LL x=1;
for(;P;P>>=1)
{
if(P&1)x=(x*B)%Mod;
B=(B*B)%Mod;
}
return x;
}
LL Inv(LL x)
{
return Pow(x,Mod-2);
}
LL Sigma(LL L,LL R)
{
return (L+R)%Mod*(R-L+1+Mod)%Mod*Inv(2)%Mod;
}
signed main()
{
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&A[i]);
Raw[i]=A[i];
}
std::sort(Raw+1,Raw+1+n);
Tot=std::unique(Raw+1,Raw+1+n)-(Raw+1);
/*-------------块内-------------*/
for(int i=1;i<=n;i++)
{
A[i]=std::lower_bound(Raw+1,Raw+1+Tot,A[i])-Raw;
if(!mk[A[i]])mk[A[i]]=1;
else
{
nex[pos[A[i]]]=i;
pre[i]=pos[A[i]];
}
pos[A[i]]=i;
}
for(int i=1;i<=n;i++)
if(nex[i]==0)
nex[i]=n+1;
for(int i=1;i<=n;i++)
{
Ans+=1LL*(i-pre[i])*(n+1-i);
Ans%=Mod;
}
Ans=(Ans-Tot+Mod)%Mod;
LL Rem=Ans;
Ans=Ans*k%Mod;
/*-------------长度不小于整块的区间-------------*/
LL num=Sigma(1,(n*k-n+1)%Mod);
Ans=(Ans+num*Tot)%Mod;
/*-------------块与块交界处-------------*/
if(k>1)
{
for(int i=n+1;i<=2*n;i++)
A[i]=A[i-n];
memset(pre,0,sizeof(pre));
memset(nex,0,sizeof(nex));
memset(mk,0,sizeof(mk));
memset(pos,0,sizeof(pos));
for(int i=1;i<=2*n;i++)
{
if(!mk[A[i]])mk[A[i]]=1;
else
{
nex[pos[A[i]]]=i;
pre[i]=pos[A[i]];
}
pos[A[i]]=i;
}
for(int i=1;i<=2*n;i++)
if(nex[i]==0)
nex[i]=2*n+1;
LL Tem=0;
for(int i=1;i<=2*n;i++)
{
Tem+=1LL*(i-pre[i])*(2*n+1-i);
Tem%=Mod;
}
Tem-=2*Rem;
Tem-=Sigma(1,n*2-n+1)*Tot;
Tem=((Tem%Mod)+Mod)%Mod;
Ans+=Tem*(k-1);
}
printf("%lld",Ans%Mod);
return 0;
}
路径计数机
考虑把问题转化为"给定树上若干条链,求有多少对链相交".
不妨令(F(S))表示(S)这个链的集合中有多少对链相交.
这个问题可以根据树上两链相交,一定有一条链两端点的LCA
在另一条链上这个性质来求解.
考虑集合(A)包含所有长度为(p)的链,集合(B)包含所有长度为(q)的链.那么答案为(F(Aor B)-(F(A)+F(B)))
树链剖分维护,时间复杂度(O(n^2log^2 n)).
#include<bits/stdc++.h>
#define LL long long
#define int long long
const int SIZE=6005;
int In()
{
char ch=getchar();
int x=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
int n,p,q,head[SIZE],nex[SIZE],to[SIZE],Tot;
int son[SIZE],Siz[SIZE],Dep[SIZE],F[SIZE],ID[SIZE],Top[SIZE],new_node;
struct Tree
{
int sum[SIZE*4],Tag[SIZE*4];
#define LC(x) (x<<1)
#define RC(x) (x<<1|1)
#define Mid ((L+R)>>1)
void push_up(int x){sum[x]=sum[LC(x)]+sum[RC(x)];}
void Do(int x,int L,int R,int K)
{
sum[x]+=(R-L+1)*K;
Tag[x]+=K;
}
void push_down(int x,int L,int R)
{
if(Tag[x])
{
Do(LC(x),L,Mid,Tag[x]);
Do(RC(x),Mid+1,R,Tag[x]);
Tag[x]=0;
}
}
void Change(int x,int L,int R,int X,int Y,int K)
{
if(L>Y||R<X)return;
if(L>=X&&R<=Y)
{
Do(x,L,R,K);
return;
}
push_down(x,L,R);
Change(LC(x),L,Mid,X,Y,K);
Change(RC(x),Mid+1,R,X,Y,K);
push_up(x);
}
int Query(int x,int L,int R,int X,int Y)
{
if(L>Y||R<X)return 0;
if(L>=X&&R<=Y)return sum[x];
push_down(x,L,R);
return Query(LC(x),L,Mid,X,Y)+Query(RC(x),Mid+1,R,X,Y);
}
}T;
void Link(int u,int v)
{
nex[++Tot]=head[u];head[u]=Tot;to[Tot]=v;
nex[++Tot]=head[v];head[v]=Tot;to[Tot]=u;
}
void DFS1(int u)
{
Siz[u]=1;
for(int i=head[u];i;i=nex[i])
{
int v=to[i];
if(Dep[v])continue;
Dep[v]=Dep[u]+1;
F[v]=u;
DFS1(v);
Siz[u]+=Siz[v];
if(Siz[v]>Siz[son[u]])
son[u]=v;
}
}
void DFS2(int u,int TOP)
{
ID[u]=++new_node;
Top[u]=TOP;
if(Siz[u]==1)return;
DFS2(son[u],TOP);
for(int i=head[u];i;i=nex[i])
{
int v=to[i];
if(v==F[u]||v==son[u])continue;
DFS2(v,v);
}
}
void mk(int u,int v,int K)
{
while(Top[u]!=Top[v])
{
if(Dep[Top[u]]<Dep[Top[v]])
std::swap(u,v);
T.Change(1,1,n,ID[Top[u]],ID[u],K);
u=F[Top[u]];
}
if(Dep[u]<Dep[v])
std::swap(u,v);
T.Change(1,1,n,ID[v],ID[u],K);
}
int sum(int u,int v)
{
int x=0;
while(Top[u]!=Top[v])
{
if(Dep[Top[u]]<Dep[Top[v]])
std::swap(u,v);
x+=T.Query(1,1,n,ID[Top[u]],ID[u]);
u=F[Top[u]];
}
if(Dep[u]<Dep[v])
std::swap(u,v);
x+=T.Query(1,1,n,ID[v],ID[u]);
return x;
}
int LCA(int u,int v)
{
while(Top[u]!=Top[v])
{
if(Dep[Top[u]]<Dep[Top[v]])
std::swap(u,v);
u=F[Top[u]];
}
if(Dep[u]>Dep[v])
std::swap(u,v);
return u;
}
int Dis(int u,int v,int L)
{
return Dep[u]+Dep[v]-2*Dep[L];
}
struct node
{
int u,v,L;
}G[9000005];
int A[9000005],B[9000005],C,C1,C2;
signed main()
{
scanf("%lld%lld%lld",&n,&p,&q);
int u,v;
for(int i=1;i<n;i++)
{
scanf("%lld%lld",&u,&v);
Link(u,v);
}
Dep[1]=1;
DFS1(1);
DFS2(1,1);
for(int u=1;u<=n;u++)
for(int v=1;v<u;v++)
{
int L=LCA(u,v);
G[++C]=(node){u,v,L};
if(Dis(u,v,L)==p)
{
A[++C1]=C;
}
if(Dis(u,v,L)==q)
{
B[++C2]=C;
}
}
LL Ans=0,Ans1=0,Ans2=0;
/**************************************/
for(int i=1;i<=C1;i++)
mk(G[A[i]].L,G[A[i]].L,1);
for(int i=1;i<=C1;i++)
Ans1+=sum(G[A[i]].u,G[A[i]].v);
for(int i=1;i<=n;i++)
{
int Tem=sum(i,i);
Ans1-=Tem*(Tem-1)/2;
}
for(int i=1;i<=C1;i++)
mk(G[A[i]].L,G[A[i]].L,-1);
/**************************************/
for(int i=1;i<=C2;i++)
mk(G[B[i]].L,G[B[i]].L,1);
for(int i=1;i<=C2;i++)
Ans2+=sum(G[B[i]].u,G[B[i]].v);
for(int i=1;i<=n;i++)
{
int Tem=sum(i,i);
Ans2-=Tem*(Tem-1)/2;
}
/**************************************/
for(int i=1;i<=C1;i++)
mk(G[A[i]].L,G[A[i]].L,1);
for(int i=1;i<=C1;i++)
Ans+=sum(G[A[i]].u,G[A[i]].v);
for(int i=1;i<=C2;i++)
Ans+=sum(G[B[i]].u,G[B[i]].v);
for(int i=1;i<=n;i++)
{
int Tem=sum(i,i);
Ans-=1LL*Tem*(Tem-1)/2;
}
Ans=Ans-Ans1-Ans2;
Ans=1LL*C1*C2-Ans;
Ans*=4;
printf("%lld",Ans);
return 0;
}
排列计数机
略.