与其被自己的本性牵着走而痛苦,倒不如试着改变自己。

前言

首先自我检讨一下,T1的部分分是原题,但是我这个 FW 居然没有看出来。。(主要是我看错题了)

论语文素养如何限制 OI 水平 别人眼里是一棵树,我眼里是一堆柱子。

T1 玩具

解题思路

预处理 dp[i][j] 表示 i 个点的森林,有 j 个点在第一棵树的概率,转移的时候考虑第 i 个点是否在第一棵子树中。

可以得到状态转移方程:\(dp_{i,j}=dp_{i-1,j-1}\times (j-1)\times inv_i+dp_{i-1,j}\times (i-j)\times inv_i\)

然后用 f[i][j]g[i][j] 分别表示有 i 个点的树或者森林深度不超过 j 的概率。

那么 \(f_{i,j}\) 可以直接从 \(g_{i-1,j-1}\) 转移过来,可以理解为,把森林中所有树的根节点都连为 新加入节点的子节点就好了。

对于 g 数组的转移考虑从一棵树和一个森林中转移:

\[g_{i,j}=\sum\limits_{k=1}^i f_{k,j}\times g_{i-k,j}\times dp_{i,k}
\]

然后在处理时候注意边界问题,以及用之前的状态更新以后的就好了。

code

70pts

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=210;
int n,mod,ans,base=1,f[N][N],c[N][N];
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
void get_C()
{
for(int i=0;i<N;i++)
{
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
int ksm(int a,int b)
{
int answer=1;
while(b)
{
if(b&1)
answer=(a*answer)%mod;
a=(a*a)%mod;
b>>=1;
}
return answer%mod;
}
signed main()
{
n=read();
mod=read();
get_C();
f[1][1]=f[2][2]=1;
for(int i=3;i<=n;i++)
for(int j=2;j<=n;j++)
{
for(int p=1;p<=i-2;p++)
for(int q=1;q<=min(j-2,p);q++)
f[i][j]=(f[i][j]+f[p][q]*f[i-p][j]%mod*c[i-2][p-1]%mod)%mod;
for(int p=1;p<=i-1;p++)
for(int q=1;q<=j;q++)
f[i][j]=(f[i][j]+f[p][j-1]*f[i-p][q]%mod*c[i-2][p-1]%mod)%mod;
}
for(int i=1;i<n;i++)
base=base*i%mod;
for(int i=2;i<=n;i++)
ans=(ans+(i-1)*f[n][i]%mod)%mod;
// cout<<ans<<' '<<base<<endl;
printf("%lld",ans*ksm(base,mod-2)%mod);
return 0;
}

正解

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=210;
int n,mod,ans,inv[N],f[N][N],dp[N][N],g[N][N];
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
void get_inv()
{
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++)
inv[i]=((mod-mod/i)*inv[mod%i])%mod;
}
signed main()
{
n=read();
mod=read();
get_inv();
dp[1][1]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++)
dp[i][j]=(dp[i-1][j-1]*(j-1)%mod*inv[i]%mod+dp[i-1][j]*(i-j)%mod*inv[i]%mod)%mod;
for(int i=0;i<=n;i++)
f[1][i]=g[0][i]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<i;j++)
{
g[i][j]=0;
for(int k=1;k<=i;k++)
g[i][j]=(g[i][j]+f[k][j]*g[i-k][j]%mod*dp[i][k]%mod)%mod;
// cout<<g[i][j]<<endl;
f[i+1][j+1]=g[i][j];
for(int k=j+1;k<=n;k++)
f[i+1][k]=f[i+1][j+1];
for(int k=i;k<=n;k++)
g[i][k]=g[i][j];
}
for(int i=2;i<=n;i++)
ans=(ans+(i-1)*(f[n][i-1]-f[n][i-2]+mod)%mod)%mod;
printf("%lld",ans);
return 0;
}

T2 y

解题思路

这里借鉴了一下 cty dalao的做法。

因为空间时间卡的都比较紧,因此我们考虑把距离为 d 的路径掰成两半来考虑

f[i][j][sta]表示走了 i 步,到了 j 点状态为 sta 的情况是否存在。

首先考虑前 \(\dfrac{d}{2}\) 的,因为只能从 1 节点出发,所以边界只能是 \(f_{0,1,0}=true\)

然后就是枚举顺序了,不难发现第一层一定是步数(毕竟我们的 DP 方程都是从前一步转移过来的吗)

接下来点以及它所联通的边,进而枚举每一步状态(注意这里应该是 |而不是直接的=,到达这种状态的方式不只有一种)

对于这一次的每一个结尾点,将它可以有的状态压进一个 vector 数组。

剩下的 \(\dfrac{d}{2}\) 与上面的类似,但是要反着,从 n 个结尾点向前进行更新。

因此,起始点就可以是任意一个点了,所以边界就要把所有的 \(f_{0,i,0}\) 都赋值为 true。

并且和上一次一样把状态压入一个 vector 。

接下来就比较简单了,就是把两段路径合并了,这里需要记录一下。

因为对于两段路径的计算是分离的,并且我们仅仅想要路径的种类数,因此状压的状态的正反无需考虑。

代码的实现细节诶不是很多,注意压 vector 的时候不要写进大循环里,不然就会 TLE ,单独拎出来处理就好了。

code

#include<bits/stdc++.h>
#define int long long
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=100,M=N*(N-1);
int n,m,dist,ans;
int tot,head[N],nxt[M<<1],ver[M<<1],edge[M<<1];
bool f[15][N][1<<12],f2[15][N][1<<12],vis[1<<22];
vector<int> v[N],v2[N];
void add_edge(int x,int y,int val)
{
ver[++tot]=y;
edge[tot]=val;
nxt[tot]=head[x];
head[x]=tot;
}
signed main()
{
// freopen("date.in","r",stdin);
n=read();
m=read();
dist=read();
for(int i=1,x,y,val;i<=m;i++)
{
x=read();
y=read();
val=read();
add_edge(x,y,val);
add_edge(y,x,val);
}
f[0][1][0]=true;
for(int k=0;k<(dist+1)/2;k++)
for(int i=1;i<=n;i++)
{
for(int j=head[i];j;j=nxt[j])
{
int to=ver[j],col=edge[j];
for(int sta=0;sta<(1<<((dist+1)/2));sta++)
{
f[k+1][to][sta<<1|col]|=f[k][i][sta];
// if(f[k+1][to][sta<<1|col])
// cout<<i<<' '<<to<<' '<<col<<' '<<k<<' '<<sta<<endl;
// cout<<"F1: "<<i<<' '<<to<<' '<<col<<' '<<k<<' '<<sta<<endl;
}
}
}
for(int i=1;i<=n;i++)
for(int sta=0;sta<(1<<((dist+1)/2));sta++)
if(f[(dist+1)/2][i][sta])
v[i].push_back(sta);
for(int i=1;i<=n;i++)
f2[0][i][0]=true;
for(int k=0;k<dist-(dist+1)/2;k++)
for(int i=1;i<=n;i++)
{
for(int j=head[i];j;j=nxt[j])
{
int to=ver[j],col=edge[j];
for(int sta=0;sta<(1<<(dist-(dist+1)/2));sta++)
{
f2[k+1][to][sta<<1|col]|=f2[k][i][sta];
// if(f2[k+1][to][sta<<1|col]) f();
// if(f2[k+1][to][sta<<1|col])
// cout<<i<<' '<<to<<' '<<col<<' '<<k<<' '<<sta<<endl;
// cout<<"F2: "<<i<<' '<<to<<' '<<col<<' '<<k<<' '<<sta<<endl;
}
}
}
for(int i=1;i<=n;i++)
for(int sta=0;sta<(1<<(dist-(dist+1)/2));sta++)
if(f2[dist-(dist+1)/2][i][sta])
v2[i].push_back(sta);
for(int k=1;k<=n;k++)
{
for(int i=0;i<v[k].size();i++)
{
for(int j=0;j<v2[k].size();j++)
{
vis[v[k][i]<<(dist-(dist+1)/2)|v2[k][j]]=true;
}
}
}
for(int i=0;i<(1<<dist);i++)
ans+=vis[i];
printf("%lld",ans);
return 0;
}

T3 z

大坑未补

7.19考试总结(NOIP模拟20)[玩具·y·z]的更多相关文章

  1. [考试总结]noip模拟20

    第五场,再挂分就没了.. 然后就没了.. 考场上一直想方法. 似乎想到了 \(T1\) 正解. 然而几个 \(k\) 的调试信息都让我迷失了自我. 然后有几句啥都没用的语句加在了上面.. 挂分... ...

  2. 2021.8.19考试总结[NOIP模拟44]

    T1 emotional flutter 把脚长合到黑条中. 每个黑条可以映射到统一区间,实际操作就是左右端点取模.长度大于$k$时显然不合法. 然后检查一遍区间内有没有不被黑条覆盖的点即可. 区间端 ...

  3. NOIP 模拟 $20\; \rm y$

    题解 \(by\;zj\varphi\) 首先发现一共最多只有 \(2^d\) 种道路,那么可以状压,(不要 \(dfs\),会搜索过多无用的状态) 那么设 \(f_{i,j,k}\) 为走 \(i\ ...

  4. 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]

    6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...

  5. 5.23考试总结(NOIP模拟2)

    5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...

  6. 5.22考试总结(NOIP模拟1)

    5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...

  7. Noip模拟20 2021.7.19

    T1 玩具 题目读错意思直接报零... 拼接方式没读懂以为是个数学题,用卡特兰数,可是的确想多了 数据范围表达出你怎么暴力都行,选择$n^3,dp$ 相当于一片森林,每次多加一条边就合并成一棵树 在$ ...

  8. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

  9. [考试总结]noip模拟23

    因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...

  10. 2021.9.13考试总结[NOIP模拟52]

    T1 路径 考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$. $code:$ 1 #include<bit ...

随机推荐

  1. 国产gowin开发板GW1NR-9K的PSRAM使用说明

    开发板子采用GW1NNR-LV9LQ144PC6/I5 FPGA器件.具有低功耗,瞬时启动,高安全性,低成本,方便扩展等特点.本开发板价格价格便宜,板子扩张性容易,帮助用户比较快速进入国产FPGA学习 ...

  2. Spring JDBCTemplet通用RowMapper帮助类

    1 import java.lang.reflect.Method; 2 import java.math.BigDecimal; 3 import java.math.BigInteger; 4 i ...

  3. Java实现银行存取款

    "感谢您阅读本篇博客!如果您觉得本文对您有所帮助或启发,请不吝点赞和分享给更多的朋友.您的支持是我持续创作的动力,也欢迎留言交流,让我们一起探讨技术,共同成长!谢谢!" 代码 `` ...

  4. 安装两个jdk Windows系统

    安装两个jdk Windows系统 本来装的是Java 8,现在有一个新的项目要到手上,需要的环境是Java 7,想着还有别的要用,所以就装两个在电脑上 jdk的下载直接去官网就行,不知道怎么下就看这 ...

  5. 力扣1(java&python)-两数之和(简单)

    题目: 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答案.但是, ...

  6. MaxCompute笛卡尔积逻辑的参数优化&复杂JOIN逻辑优化

    简介: 这篇文章主要讲一个SQL优化反映的两个优化点.分别是: 一.笛卡尔积逻辑的参数优化. 二.一个复杂JOIN逻辑的优化思路. 1.  优化概述 最近协助一个项目做下优化任务的工作.因为主要数据都 ...

  7. Docker部署Node应用简单实践

    简介: 本文将从零至一,介绍如何在云服务器上通过 Docker 容器运行一个简单的Node应用. 前言 本文将从零至一,介绍如何在云服务器上通过 Docker 容器运行一个简单的Node应用.本文假设 ...

  8. 盒马新零售基于DataWorks搭建数据中台的实践

    大家好,我叫许日花名欢伯,在2016年盒马早期的时候,我就转到了盒马的事业部作为在线数据平台的研发负责人,现在阿里云的计算平台负责DataWorks的建模引擎团队.今天的分享内容也来源于另一位嘉宾李启 ...

  9. [Caddy2] Caddyfile 指令

    以下是 Caddyfile 的标准指令. acme_server An embedded ACME server basicauth Enforces HTTP Basic Authenticatio ...

  10. [PHP] 浅谈 Laravel Scout 的存在意义

    注:Laravel Scout 是官方支持的对框架模型数据进行全文检索功能的扩展包. Laravel 的 Scout 与 Eloquent ORM 进行了深度集成,不用开发者再自己进行代码侵入了. L ...