2021.9.30 Codeforces 中档题四道
Codeforces 1528D It's a bird! No, it's a plane! No, it's AaParsa!(*2500)
考虑以每个点为源点跑一遍最短路,每次取出当前距离最小的点然后更新一圈周围的点,具体更新方法是:设 \(p\) 为当前这一轮我们取出的点,那么显然对于一条本来由 \(p\to q\),权值为 \(c\) 的边以及另一个点 \(r\),有 \(d_r\leftarrow\min(d_r,c+d_p+(r-q+d_p)\bmod n)\),直接松弛单次复杂度平方,显然过劣,稍微想想可以发现这东西等价于圆周上的距离,因此顺时针扫两遍即可线性松弛。注意由于这题边数可以达到 \(n^2\),是个稠密图,因此加上堆优化复杂度反而多一个 \(\log\),应用不带堆优化的 dijkstra,总复杂度 \(n^3\)。
const int MAXN=600;
int n,m,c[MAXN+5][MAXN+5];
bool vis[MAXN+5];ll d[MAXN+5][MAXN+5];
int get(int x){return (x>=n)?(x-n):x;}
int main(){
scanf("%d%d",&n,&m);
memset(c,63,sizeof(c));memset(d,63,sizeof(d));
for(int i=1,u,v,w;i<=m;i++) scanf("%d%d%d",&u,&v,&w),chkmin(c[u][v],w);
for(int i=0;i<n;i++){
d[i][i]=0;memset(vis,0,sizeof(vis));
for(int j=0;j<n;j++){
int p=n;
for(int k=0;k<n;k++) if(!vis[k]&&d[i][k]<d[i][p]) p=k;
vis[p]=1;int mn=INF,rem=d[i][p]%n;
for(int k=0;k<n*2;k++){
++mn;
chkmin(mn,c[p][get(get(k)-rem+n)]);
chkmin(d[i][get(k)],d[i][p]+mn);
}
}
for(int j=0;j<n;j++) printf("%lld%c",d[i][j]," \n"[j==n-1]);
}
return 0;
}
Codeforces 1528E Mashtali and Hagh Trees(*2900)
首先手玩几组数据可以发现一棵有向树满足第三个条件(也就是那个朋友的条件)当且仅当它是一棵外向树或是一棵内向树或是一个外向树与一个内向树用一条内向树根指向外向树根的边相连。考虑如何算之:
- 外向树与内向树求法是相同的,对于每棵外向树如果把其所有边都反向,即可形成一棵内向树,因此外向树个数 \(=\) 内向树个数,而一条有向链即是外向树也是内向树,因此第一、二类树的个数总和就是符合要求的外向树个数的两倍减 \(1\)。我们设 \(dp_i\) 表示有多少棵不同构的树满足最大深度为 \(i\) 且每个点儿子个数 \(\le 2\)(根节点深度为 \(0\)),转移就分根有一个儿子和根有两个儿子即可,即 \(dp_i=dp_{i-1}+\sum\limits_{j=0}^{i-2}dp_jdp_{i-1}+\dfrac{dp_{i-1}(dp_{i-1}+1)}{2}\)。那么由于根节点儿子个数可以达到 \(3\),因此最大深度为 \(n\) 的内向树个数需进行一些分类讨论:
- 如果根节点儿子个数 \(\le 1\),方案数就是 \(dp_n\)。
- 如果根节点儿子个数 \(=2\),那么设根节点三个儿子最大深度分别为 \(a,b,c(a\le b\le c)\),那么必须有 \(c=n\)。但是由于 \(\le\) 这个条件的存在,有可能会算重,需要分 \(a<b<c,a=b<c,a<b=c,a=b=c\) 四种情况再进行分类讨论。
- 对于第三种情况,我们定义一个点的深度为入度为 \(0\) 的点到其的最长距离,那么我们考虑枚举第一个入度 \(\ge 2\) 的点的深度 \(x\),那么根向树的方案数为 \(dp_x-dp_{x-1}\),减掉的那个 \(dp_{x-1}\) 是该节点入度为 \(1\) 的情况,叶向树的方案数为 \(dp_{n-1-x}-1\),减掉的那个 \(1\) 是一条链的情况,这时候的贡献已经在叶向树中计算过了。
时间复杂度线性。
const int INV2=MOD+1>>1;
const int INV6=(MOD+1)/6;
const int MAXN=1e6;
int n,dp[MAXN+5];
int main(){
scanf("%d",&n);dp[0]=1;
for(int i=1,sum=0;i<=n;i++){
dp[i]=1ll*dp[i-1]*sum%MOD;
dp[i]=(dp[i]+1ll*dp[i-1]*(dp[i-1]+1)%MOD*INV2)%MOD;
dp[i]=(dp[i]+dp[i-1])%MOD;sum=(sum+dp[i-1])%MOD;
// printf("%d %d\n",i,dp[i]);
} int ss=0;
for(int i=0,s=0;i<n-1;i++){
ss=(ss+1ll*s*dp[i])%MOD;
s=(s+dp[i])%MOD;
} int res=1ll*ss*dp[n-1]%MOD;
for(int i=0;i<n-1;i++) res=(res+1ll*dp[n-1]*dp[i]%MOD*(dp[i]+1)%MOD*INV2)%MOD;
for(int i=0;i<n-1;i++) res=(res+1ll*dp[n-1]*(dp[n-1]+1)%MOD*INV2%MOD*dp[i])%MOD;
res=(res+1ll*dp[n-1]*(dp[n-1]-1)%MOD*(dp[n-1]-2)%MOD*INV6)%MOD;
res=(res+1ll*dp[n-1]*(dp[n-1]-1))%MOD;res=(res+dp[n-1])%MOD;
res=(res+dp[n])%MOD;res=(res*2)%MOD;
for(int i=1;i<n-1;i++) res=(res+1ll*(dp[i]-1)*(dp[n-1-i]-dp[n-2-i]+MOD))%MOD;
printf("%d\n",(res-1+MOD)%MOD);
return 0;
}
Codeforces 1511F Chainword(*2700)
因为昨天做过了这场的 G,今天就顺便把 F 做了(
这道题就很套路了吧。。。
建出 \(n\) 个串的 trie,然后设 \(dp_{i,j}\) 表示目前第一段拼成的串的长度为 \(i\),第二段划分到 trie 树上第 \(j\) 个节点的方案数,然后发现转移只会从前面 \(5\) 个位置转移过来,于是开一个 \(5\times 5\times 8\) 的矩阵维护转移情况即可。由于字符串长度很小,转移矩阵可以大力暴搜求出。然后矩阵快速幂即可。
时间复杂度 \(|S|^6n^3\log m\)。
const int MAXN=8;
const int MAXP=41;
const int MAXL=5;
const int MAXS=215;
int n,m,ch[MAXP+5][27],ncnt=1,tot,ed[MAXP+5];
string s[MAXN+2];
void insert(string str){
int cur=1;
for(int i=0;i<str.size();i++){
if(!ch[cur][str[i]-'a']) ch[cur][str[i]-'a']=++ncnt;
cur=ch[cur][str[i]-'a'];
} ed[cur]=1;
}
struct mat{
u64 a[MAXS+5][MAXS+5];
mat(){memset(a,0,sizeof(a));}
mat operator *(const mat &rhs){
mat res;
for(int i=1;i<=tot;i++) for(int k=1;k<=tot;k++) for(int j=1;j<=tot;j++){
res.a[i][j]+=a[i][k]*rhs.a[k][j];
if((k&15)==0) res.a[i][j]%=MOD;
}
for(int i=1;i<=tot;i++) for(int j=1;j<=tot;j++) res.a[i][j]%=MOD;
return res;
}
void print(){
for(int i=1;i<=tot;i++) for(int j=1;j<=tot;j++)
printf("%llu%c",a[i][j]," \n"[j==tot]);
}
} trs,res;
int a[MAXL+2][MAXP+5][MAXP+5];
void dfsclc(int p,int id,int len,int ori){
if(ed[p]&&len!=0) dfsclc(1,id,len,ori);
if(len==s[id].size()) return a[len][ori][p]++,void();
if(ch[p][s[id][len]-'a']) dfsclc(ch[p][s[id][len]-'a'],id,len+1,ori);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
static char orzczx[MAXL+4];
scanf("%s",orzczx+1);int len=strlen(orzczx+1);
for(int j=1;j<=len;j++) s[i].pb(orzczx[j]);
insert(s[i]);
} tot=ncnt*5;
for(int i=1;i<=ncnt;i++) for(int j=1;j<=n;j++) dfsclc(i,j,0,i);
for(int i=1;i<=4;i++) for(int j=1;j<=ncnt;j++) trs.a[j+i*ncnt][j+(i-1)*ncnt]=1;
for(int i=1;i<=5;i++) for(int j=1;j<=ncnt;j++) for(int k=1;k<=ncnt;k++)
trs.a[(5-i)*ncnt+j][4*ncnt+k]=a[i][j][k];
// trs.print();
for(int i=1;i<=tot;i++) res.a[i][i]=1;
for(;m;m>>=1,trs=trs*trs) if(m&1) res=res*trs;
printf("%d\n",res.a[4*ncnt+1][4*ncnt+1]);
return 0;
}
Codeforces 1495D BFS Trees(*2600)
先考虑怎样求出一个点 \(x\) 的 BFS Tree 的数量。考虑将点按 \(x\) 到其的最短距离分层,那么显然每个点在 BFS Tree 上的父亲必须是某个上一层的节点,而如果我们钦定每个点都连向一个上一层的节点,那显然会形成一个树形结构,因此方案数就是对于与每个不同于源点的点 \(x\),与其相连的在其上一层的节点个数之积。
接下来考虑求解原问题。注意到对于两个点 \(i,j\),如果存在两个不同的点 \(x,y\),满足 \(dis_{i,x}+dis_{x,j}=dis_{i,j},dis_{i,y}+dis_{y,j}=dis_{i,j}\),且 \(dis_{i,x}=dis_{i,y}\) 那么答案肯定是 \(0\),因为 \(i\to x,x\to j,i\to y,y\to j\) 最短路上的节点肯定都要在 BFS Tree 上,这样构不成树形结构,否则对于在 \(i,j\) 最短路径上的点,它们之间的连边情况肯定是唯一的,我们就把它们缩起来然后跑前面的子问题即可。
实现时不必真的缩,只用统计对于某个不在 \(i,j\) 最短路上的点 \(x\),有多少个与之相连的点 \(y\) 满足 \(dis_{i,x}=dis_{i,y}+1,dis_{j,x}=dis_{j,y}+1\)。
时间复杂度 \(n^2m\)。
const int MAXN=400;
const int MAXM=600;
int n,m,dis[MAXN+5][MAXN+5];
link_list<int,MAXN,MAXM*2> g;
bool vis[MAXN+5];
int main(){
scanf("%d%d",&n,&m);memset(dis,63,sizeof(dis));
for(int i=1;i<=n;i++) dis[i][i]=0;
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);dis[u][v]=dis[v][u]=1;
g.ins(u,v);g.ins(v,u);
}
for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
chkmin(dis[i][j],dis[i][k]+dis[k][j]);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
memset(vis,0,sizeof(vis));bool ban=0;
for(int k=1;k<=n;k++) if(dis[i][j]==dis[i][k]+dis[k][j]){
if(vis[dis[i][k]]){ban=1;break;}
vis[dis[i][k]]=1;
} int res=1;
if(!ban){
for(int k=1;k<=n;k++) if(dis[i][j]!=dis[i][k]+dis[k][j]){
int cnt=0;
for(int e=g.hd[k];e;e=g.nxt[e]){
int f=g.val[e];
if(dis[i][f]+1==dis[i][k]&&dis[j][f]+1==dis[j][k]) cnt++;
} res=1ll*res*cnt%MOD;
}
} printf("%d%c",(ban)?0:res," \n"[j==n]);
}
return 0;
}
2021.9.30 Codeforces 中档题四道的更多相关文章
- Codeforces 杂题集 2.0
记录一些没有写在其他随笔中的 Codeforces 杂题, 以 Problemset 题号排序 1326D2 - Prefix-Suffix Palindrome (Hard version) ...
- 2021.11.30 eleveni的水省选题的记录
2021.11.30 eleveni的水省选题的记录 因为eleveni比较菜,eleveni决定先刷图论,再刷数据结构,同时每天都要刷dp.当然,对于擅长的图论,eleveni决定从蓝题开始刷.当然 ...
- 2021.08.30 前缀函数和KMP
2021.08.30 前缀函数和KMP KMP算法详解-彻底清楚了(转载+部分原创) - sofu6 - 博客园 (cnblogs.com) KMP算法next数组的一种理解思路 - 挠到头秃 - 博 ...
- Codeforces刷题计划
Codeforces刷题计划 已完成:-- / -- [Codeforces370E]370E - Summer Reading:构造:(给定某些数,在空白处填数,要求不下降,并且相邻差值<=1 ...
- FFT/NTT中档题总结
被DeepinC%怕了,把一些题放到这里来 T1Normal 其实这道题放到中档题也不太合适,个人感觉真的很难,机房里好像都是颓的题解 因为期望的可加性,把每个点的贡献单独处理,即求期望深度 考虑$y ...
- Educational Codeforces Round 30 A[水题/数组排序]
A. Chores time limit per test 2 seconds memory limit per test 256 megabytes input standard input out ...
- Codeforces 939A题,B题(水题)
题目链接:http://codeforces.com/problemset/problem/939/A A题 A. Love Triangle time limit per test 1 second ...
- Codeforces水题集合[14/未完待续]
Codeforces Round #371 (Div. 2) A. Meeting of Old Friends |B. Filya and Homework A. Meeting of Old Fr ...
- 屏蔽Codeforces做题时的Problem tags提示
当在Codeforces上做题的时,有时会无意撇到右侧的Problem tags边栏,但是原本并不希望能够看到它. 能否把它屏蔽了呢?答案是显然的,我们只需要加一段很短的CSS即可. span.tag ...
随机推荐
- Java 读取PDF中的表格
一.概述 本文以Java示例展示读取PDF中的表格的方法.这里导入Spire.PDF for Javah中的jar包,并使用其提供的相关及方法来实现获取表格中的文本内容.下表中整理了本次代码使用到的主 ...
- 半天撸一个简易版mybatis
为什么需要持久层框架? 首先我们先看看使用原生jdbc存在的问题? public static void main(String[] args) { Connection connection = n ...
- springcloud(二) 微服务架构编码构建
微服务架构编码构建 1 基础知识 1.1 版本 2 微服务cloud整体聚合父工程Project 2.1 new project 2.2 字符编码设置 utf-8 2.3 pom.xml 2.4 父工 ...
- BUAA_2020_软件工程_热身作业
项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 热身作业要求 我在这个课程的目标 了解软件工程的技术,掌握工程化开发的能力 这个作业在哪个具体方面 ...
- 洛谷 P3232 [HNOI2013]游走
链接: P3232 题意: 和上次考试 T4 的简化且无修改一样,经典图上高斯消元求期望. 分析: 要求出每个点的期望出发次数 \(f_i\),每个点度数为 \(d_i\),有 \[f1=\sum\d ...
- loto仪器_如何模拟输出凸轮轴和曲轴波形_用任意波形信号源SIG852?
loto仪器_如何模拟输出凸轮轴和曲轴波形_用任意波形信号源SIG852? 在汽车传感器的波形检测应用中,有时候需要模拟各种汽车传感器的输出信号,用来驱动和监测对应的执行机构或者电路是否正常,这其中, ...
- MySQL怎么缓解读的压力的?---buffer pool
每当我们想要缓解读,一般会想到什么? 预读取,缓存 缓存 缓存,其实就是将高频访问的数据放到内存里面,减少读盘的次数. 为了提高内存的利用率,MySQL还建立了缓存池,也就是buffer pool,存 ...
- anaconda无法launch应用(无法l打开任何应用)的问题解决 (点击应用无反应)
遇到了anaconda 无法launch 任何应用. 重装也不行. 先说我最终的解决方法(在官方文档中找到): 1. 启动 anaconda prompt , 输入 conda remove anac ...
- Spark面试题(四)
1.Spark中的HashShufle的有哪些不足? 1)shuffle产生海量的小文件在磁盘上,此时会产生大量耗时的.低效的IO操作: 2)容易导致内存不够用,由于内存需要保存海量的文件操作句柄和临 ...
- linux&c 进程控制 课后习题
(声明:本篇博客只是博主自己的理解,加以整理,目的是总结刚学过的进程知识,不一定绝对正确,非常愿意听客官您提出宝贵意见.) Q1:进程中的全局数据段(全局变量),局部数据段(局部变量),静态数据段的分 ...