复读数组

分成 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. JAVA架构之单点登录 任务调度 权限管理 性能优化大型项目实战

    单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任.单点登录在大型网站里使用得 ...

  2. 【STM32H7教程】第61章 STM32H7的MDMA基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第61章       STM32H7的MDMA基础知识和HAL ...

  3. mysql数据库技术1——基本的增删查改的sql语句

    1.数据库语言的分类 DDL:数据库定义语言 data Definition language 用于创建.修改.和删除数据库内的数据结构,如: 1:创建和删除数据库(CREATE DATABASE | ...

  4. C++ 实现string转BYTE

    用于将形如"0x1A"的string转成BYTE类型 代码如下, 有问题欢迎指出 bool str2byte(const std::string &str, BYTE &a ...

  5. 数据分析----天气预报走向(pygal)

    #!usr/bin/env python #-*- coding:utf-8 _*- """ @author:Administrator @file: 可视化天气预报.p ...

  6. MongoDB 添加用户名和密码

    MongoDB 添加用户名和密码 我用的是 mongodb3.6,如果没有的话先安装. sudo apt install mongodb 终端输入mongo,首先添加管理用户, show dbs // ...

  7. mysql第五课

    修改表中一行或多行数据: SELECT*FROM student;+----+------+------+| id | name | ban  |+----+------+------+|  1 | ...

  8. laravel手动数组分页

    laravel文档中已经有写如何自己使用分页类去分页了,但没有详细说明. 如果你想手动创建分页实例并且最终得到一个数组类型的结果,可以根据需求来创建 IlluminatePaginationPagin ...

  9. 解决问题:当redis服务端断开的时候`进程会崩溃(转载6哥笔记)

    package main import ( "fmt" "github.com/astaxie/beego/logs" "github.com/gar ...

  10. C#加密与解密(DES\RSA)学习笔记

    本笔记摘抄自:https://www.cnblogs.com/skylaugh/archive/2011/07/12/2103572.html,记录一下学习过程以备后续查用. 数据加密技术是网络中最基 ...