复读数组

分成 3 种区间算答案:

  1. 一个块内的区间
  2. 两个块交界处,长度小于块长的区间
  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(A\or B)-(F(A)+F(B))\)

树链剖分维护,时间复杂度\(O(n^2\log^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;
}

排列计数机

略.

牛客CSP-S提高组赛前集训营4 赛后总结的更多相关文章

  1. 牛客网CSP-S提高组赛前集训营Round4

    牛客网CSP-S提高组赛前集训营 标签(空格分隔): 题解 算法 模拟赛 题目 描述 做法 \(BSOJ6377\) 求由\(n\)长度的数组复制\(k\)次的数组里每个连续子序列出现数字种类的和 对 ...

  2. 牛客CSP-S提高组赛前集训营3 赛后总结

    货物收集 二分答案.复杂度\(O(n\log n)\). 货物分组 用费用提前计算的思想,考虑用一个新的箱子来装货物会发生什么. 显然费用会加上后面的所有货物的总重. \(60\)分的\(O(n^2) ...

  3. 牛客CSP-S提高组赛前集训营5 赛后总结

    A.无形的博弈 心理题. 答案为\(2^n\),可感性理解结论的正确性. #include<bits/stdc++.h> #define LL long long const LL Mod ...

  4. 牛客CSP-S提高组赛前集训营2 赛后总结

    比赛链接 A.服务器需求 维护每天需要的服务器数量的全局最大值(记为\(Max\))和总和(记为\(sum\)),那么答案为: \[max(Max,\lceil\dfrac{sum}{m}\rceil ...

  5. 牛客CSP-S提高组赛前集训营1

    牛客CSP-S提高组赛前集训营1 比赛链接 官方题解 before:T1观察+结论题,T2树形Dp,可以换根或up&down,T3正解妙,转化为图上问题.题目质量不错,但数据太水了~. A-仓 ...

  6. 牛客CSP-S提高组赛前集训营3

    A 货物收集 显然是一个二分答案的题. #include<iostream> #include<cstdio> #include<cstring> #include ...

  7. 牛客CSP-S提高组赛前集训营2 ———— 2019.10.31

    比赛链接 期望得分:100+20+20 实际得分:40+20+30 awa  cccc T1 :基于贪心的思路,然后开始爆搜(雾 那必然是会死的,好吧他就是死了 #include<iostrea ...

  8. 牛客CSP-S提高组赛前集训营1———2019.10.29 18:30 至 22:00

    期望得分:100+0+10 实际得分:40+0+0 考炸了... T1:题目链接 究竟为什么会这样,,, 仔细研读我的丑代码 发现... 枯辽.... #include<cstdio> # ...

  9. 牛客CSP-S提高组赛前集训营2 T2沙漠点列

    原题链接 算法不难,比赛的时候就和cyc大佬一起yy了正解,不过因为交的时候比较急(要回寝室惹),我有两数组开错大小直接爆到50,cyc大佬则只把文件输入关了一半,直接爆零(╯ ̄Д ̄)╯┻━┻ 要尽量 ...

随机推荐

  1. 前端 Docker 基本教程

    为什么要学习 Docker ? 每学一个东西,我们肯定是基于某个需求去学习的,众所周知,软件开发最麻烦的是环境配置,开发好好的,部署出问题就很难受,所以为了确保开发.测试.部署环境一致,且高效的部署所 ...

  2. CSGO控制台命令

    转帖: 按下“~”即可开启 使用时先输入参数名 然后按下SPACE空出一格 再输入设定值即可 一般玩家进入游戏都只能用到Client(玩家用参数) 不过...如果你是开LAN GAME的人 就能进阶到 ...

  3. [Contract] public、external, private、internal 在 Solidity 中如何选择

    合约内部访问的用 private,修饰内部变量时选择.通过 external 函数返回. 合约内部.外部均可访问的用 public. 仅在合约外部访问的用 external,明确暴露给前端使用时选择. ...

  4. Django基础一Web框架的本质

    我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,基于请求做出响应,客户都先请求,服务端做出对应的响应,按照http协议的请求协议发送请求, ...

  5. windows系统安装python

    1.python3 下载 官网下载:https://www.python.org百度网盘下载:https://pan.baidu.com/s/1dH0UZg_7Q-YcppR0PjUfzQ提取码:xl ...

  6. HAProxy 使用小记

    PS:写在开头,虽然HAProxy优点很多,但是现在网上可参考的HAProxy文档真的少之又少,so,我把最近在项目中使用的心得整理下,供大家参考,如有侵权或错误之处,还请联系更正,谢谢! 好了,下面 ...

  7. 【37】池化层讲解(Pooling layers)

    池化层(Pooling layers) 除了卷积层,卷积网络也经常使用池化层来缩减模型的大小,提高计算速度,同时提高所提取特征的鲁棒性,我们来看一下.   先举一个池化层的例子,然后我们再讨论池化层的 ...

  8. 深度优先搜索DFS---最优子序列求和问题(1)

    题目: 给定N 个整数(可能有负数),从中选择 K个数,使得这 K个数之和恰好等于一个给定的整数 X:如果有多种方案,那么选择它们中元素平方和最大的一个.例如,从4个整数{ 2, 3, 3 ,4}中选 ...

  9. JN_0013:win10快速回桌面

    4.最后一种方法是最为实用的方法.按快捷键[windows键+D键],如下图所示,两键同时按,或者先按住windows键不放再按D键.这种方法在任何时候都是有用的,并且熟练使用后可以达到非常快的速度: ...

  10. 【学习笔记】:一天搞定HTML

    PS:许多控制样式的标签在HTML5中都不推荐使用,建议使用CSS,如align,border等. 一.概念 HTML的英文全称:Hypertext Marked Language 超文本标记语言. ...