noip模拟测试18
打开比赛第一眼——超级树?
点开——原题
百感交集……
欣喜于发现是半年前做过两遍的原题 
紧张于如果A不了比较尴尬 
绝望于发现根本不会做了 
瞟了一眼t1,瞅了一眼t2,嗯……开始搞t3
10分钟打完暴力,开始dp退柿子。然而一个半小时过去了,发现经过一番挫折才终于想起来那个阴间的状态
上了个厕所,看了下表不早了,得开始写前面的了,好恋恋不舍~
再看t2,10分钟打了个很不确定的二分
再看t1,20分钟推了个没有证明的结论
写完都交了
看了下表大概九点半多了,感觉两个小时一事无成,但还是铁下心又回去推t3。
写了好几草稿纸的柿子,手模 \(n=3\) 的情况,老是差那么一点点……
听见隔壁大佬自言自语说t1好难处理,估计是挂了
上厕所看见好多人都在看t2,估计二分是伪了
心里想着算了吧,t3没A就没A吧,估计好多人也忘了
但一想要是现在停下来两个多小时努力就白费了
又一想这题上次也是我讲的肯定是会做哒
再一想只要A掉这道题排名肯定也不会差
于是一直推一直推直到结束也没弄出来……
于是得到了史无前例的糟糕成绩……

题解
好了好了,先回归正题~
A. 星级旅行
首先,要看出这道题的本质是求欧拉路。相当于将每条边复制一下,这时每个点的度数都成为偶数,然后去掉两条边使得整个图有欧拉路
由于这道题里光明正大地说有自环,记自环数量为 \(tot\),于是可以分为三种情况:
- 删除两个自环,这时这两个点的度数都减少2(或者一个点减少4),满足题意,答案为 \(C_{tot}^2\)
- 删除一个自环和一条边,这时边两端的点度数减少1,成为奇数度点,分别成为起点和终点,答案为 \(tot*(m-tot)\)
- 删除两条边,这时有特殊要求是这两条边有一个公共的端点,产生两个奇数度点,此时答案为 \(\sum C_{deg_i}^2\)
查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const int maxm=4e5+5;
int n,m,deg[maxn],cnt,hd[maxn],tot,num[maxn],num1,x,y;
long long ans;
bool vis[maxm];
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
struct Edge{
int nxt,to;
}edge[maxm];
void add(int u,int v){
edge[++cnt].nxt=hd[u];
edge[cnt].to=v;
hd[u]=cnt;
return ;
}
void dfs(int u,int from){
vis[u]=true;
num[from]++;
for(int i=hd[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(!vis[v])dfs(v,from);
}
return ;
}
int main(){
n=read();
m=read();
// cnt=1;
int root=0;
for(int i=1;i<=m;i++){
x=read();
y=read();
if(x==y){
tot++;
}
else{
add(x,y);
add(y,x);
root=i;
deg[x]++;
deg[y]++;
}
}
for(int i=1;i<=n;i++){
dfs(i,i);
}
for(int i=1;i<=n;i++){
if(num[i]>1)num1++;
}
if(num1>1||tot==m){
cout<<0;
return 0;
}
ans=1ll*tot*(m-tot);
ans+=1ll*tot*(tot-1)/2;
for(int i=1;i<=n;i++){
if(deg[i]>=2)ans+=1ll*deg[i]*(deg[i]-1)/2;
}
cout<<ans;
return 0;
}
B. 砍树
首先说一下错误的做法——二分
这题其实没有单调性(取模运算似乎往往都没有)
比如可以举出栗子
5 10 25
当模数取5的时候答案灰常小,而模数取4和6的时候又会很大
其实嘛……这是一个老老实实推柿子的题
这道题需要满足的条件是
\(\sum_{i=1}^{n} d-(a_i \%d)\le k\),其中1求和部分当 \(a_i\) 模d等于0时以0计算
\(d-\sum_{i=1}^{n} a_i-\left \lfloor \frac{a_i}{d} \right \rfloor * d \le k\)
\(d*n-sum+\sum_{i=1}^{n} \left \lfloor \frac{a_i}{d} \right \rfloor * d \le k\)
\(\sum_{i=1}^{n} \left \lfloor \frac{a_i}{d} \right \rfloor \le \left \lfloor \frac{k+sum}{d} \right \rfloor -n\)
现在再观察柿子,发现右边 \(k+sum\) 和 \(n\) 都是定值,而除 \(d\) 取整特别难受
于是可以想到一个高级科技——整除分块儿~
右边分块后会有根号种取值,每种取值对应 \(d\) 的一段连续区间 \(\left [l,r \right ]\),暴力计算左边验证是否满足条件
观察左式,当 \(d\) 越大时值越小,也越容易满足条件,于是每次只需要贪心地选取区间的 \(r\) 进行验证并更新答案即可
查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
#define int long long
int n,k,a[maxn],sum,tot,ans,l,r,x;
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
bool check(int limit){
int sum1=0;
for(int i=1;i<=n;i++){
int x=a[i]%limit;
if(!x)x=limit;
sum1+=limit-x;
}
if(sum1<=k)return true;
return false;
}
signed main(){
n=read();
k=read();
for(int i=1;i<=n;i++){
a[i]=read();
sum+=a[i];
}
tot=sum+k;
// cout<<check(3);
// cout<<tot<<endl;
while(r<tot){
l=r+1;
x=tot/l;
r=min(tot/x,tot);
// cout<<l<<" "<<r<<" "<<check(r)<<endl;
if(check(r))ans=max(ans,r);
}
cout<<ans;
return 0;
}
C. 超级树
咳咳——这道恶心的题
这回细细地写一下这道题
首先说一下为什么状态不能设计成一维的

像上图一样,在处理当前节点是会有很儿子节点中的两条路径与根节点拼接形成新的路径,而一维状态只能处理当前层节点的信息,于是显然不适用
于是改进,状态为:\(f_{i,j}\) 表示 \(i\) 级超级树中存在 \(j\) 条互不相交的路径的方案数
则答案是 \(f_{k,1}\)
再来看转移,首先观察超级树,长得有一个特点——就是根节点将树劈成了两半,而横跨根节点的路径最多一条。
于是对于 \(i\) 级超级树左子树有 \(j\) 条路径,右子树有 \(k\) 条路径,向 \(i+1\) 级超级树转移时,可以分为四种情况:
- 不选取根节点,也不拼合路径,此时大的超级树有 \(j+k\) 条路径:\(f_{i+1,j+k}+=f_{i,j}*f_{i,k}\)
- 选取根节点,不拼合路径,此时根节点自成一条路径,大的超级树有 \(j+k+1\) 条路径:\(f_{i+1,j+k+1}+=f_{i,j}*f_{i,k}\)
- 选取根节点,根节点与左或右子树中的一条路径拼合,大的超级树有 \(j+k\) 条路径,由于可以接在头也可以接在尾,需要乘2:\(f_{i+1,j+k}+=2*(j+k)*f_{i,j}*f_{i,k}\)
- 选取根节点,根节点将两条路径串联,大的超级树有 \(j+k-1\) 条路径,由于可以头接尾也可以尾接头,需要乘2:\(f_{i+1,j+k-1} += 2*C_{j+k}^{2}*f_{i,j}* f_ {i,k}\)
回头算一下时间复杂度,发现是 \(n^3\) 的,考虑优化
观察一下转移的柿子和最后的目标,由于每次升级条数最多减少1,而最终条数为1,所以满足 \(i+j+k \le n\) 即可,大大减少复杂度
查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
long long f[305][305],mod;
int main(){
cin>>n>>mod;
f[1][1]=f[1][0]=1;
for(int i=1;i<=n-1;i++){
for(int j=0;j<=n-i+1;j++){
for(int k=0;k<=n-j-i+2;k++){
f[i+1][j+k]=(f[i+1][j+k]+f[i][j]*f[i][k]%mod)%mod;
f[i+1][j+k+1]=(f[i+1][j+k+1]+f[i][j]*f[i][k]%mod)%mod;
f[i+1][j+k]=(f[i+1][j+k]+2ll*f[i][j]%mod*f[i][k]%mod*(j+k)%mod)%mod;
f[i+1][j+k-1]=(f[i+1][j+k-1]+(j+k)*(j+k-1)%mod*f[i][k]%mod*f[i][j]%mod)%mod;
}
}
}
cout<<f[n][1]%mod;
return 0;
}
Summary
平时不考不知道,一考发现竟然做过两遍的题再出来还是不会做,每场考试的改题过程存在很大的漏洞,因此:
- 看懂思路后独立完成代码
- 减少改题提交次数
- A掉题以后花时间沉淀反思
- 搜集尝试不同的思路
- 每次考试后跟进博客
而且,万一再有原题——不要惊慌,不要紧张,照常按难度做题即可——不要吊死在一棵树上~
noip模拟测试18的更多相关文章
- NOIP模拟测试18(T3待更新)
T1: 直接模拟,详见代码注释. 复杂度$O(NM)$. Code: #include<iostream> #include<cstdio> #include<vecto ...
- 2019.8.12 NOIP模拟测试18 反思总结
写个博客总是符合要求的对吧 回来以后第一次悄悄参加考试,昨天全程围观… 然后喜提爆炸120分wwwwwwwww T1用了全机房最慢的写法,导致改掉死循环T掉的一个点以后还是死活过不了最后一个点.T2全 ...
- NOIP模拟测试18「引子·可爱宝贝精灵·相互再归的鹅妈妈」
待补 引子 题解 大模拟,注意细节 代码1 #include<bits/stdc++.h> using namespace std; int n,m;char a[1005][1005]; ...
- NOIP模拟测试17&18
NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色
2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
- NOIP模拟测试1(2017081501)
好,今天是cgg第一次举行模拟测试,希望各位支持. 时间限制:2小时 题目链接: 题目一:水得都没名字了 题目二:车站 题目三:选数 不要觉得2小时太少,我的题目很良心,都很简单. 答案可以在模拟测试 ...
随机推荐
- 线性反馈移位寄存器(LFSR)
LFSR用于产生可重复的伪随机序列PRBS,该电路有n级触发器和一些异或门组成,如下图所示. 其中,gn为反馈系数,取值只能为0或1,取为0时表明不存在该反馈之路,取为1时表明存在该反馈之路:这里的反 ...
- GhostScript 沙箱绕过(命令执行)漏洞(CVE-2019-6116)
影响范围 Ghostscript 9.24之前版本 poc地址:https://github.com/vulhub/vulhub/blob/master/ghostscript/CVE-2019-61 ...
- 大数据学习(02)——HDFS入门
Hadoop模块 提到大数据,Hadoop是一个绕不开的话题,我们来看看Hadoop本身包含哪些模块. Common是基础模块,这个是必须用的.剩下常用的就是HDFS和YARN. MapReduce现 ...
- 02.反射Reflection
1. 基本了解 1.1 反射概述 文字说明 审查元数据并收集关于它的类型信息的能力称为反射,其中元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个 ...
- IDEA使用Tomcat时控制台乱码的解决方案>从零开始学JAVA系列
IDEA使用Tomcat时控制台乱码的解决方案 解决方案1,修改启动时虚拟机参数 解决方案2,修改idea的设置 解决方案3,修改idea配置文件 在最后添加一行 '-Dfile.encoding=U ...
- linux之frp服务部署(内网穿透)
frp服务部署(内网穿透) 目的 更快的进行内网穿透调试以及云端开发测试 服务器为CentOS 7,客户端为win11 frp介绍 frp 是一个开源项目, 采用 C/S 模式,将服务端部署在具有公网 ...
- 对象转换工具 MapStruct 介绍
前言 在我们日常开发的分层结构的应用程序中,为了各层之间互相解耦,一般都会定义不同的对象用来在不同层之间传递数据,因此,就有了各种 XXXDTO.XXXVO.XXXBO 等基于数据库对象派生出来的对象 ...
- CF466C 题解
Description 给定一个数组,求有多少组 \(i,j\) 将整个数组分成和相等的三个数组. Solution 从左往右看一遍,记录每一个 \(i\) 使得 \(\sum_{k=1}^i a_k ...
- PWN——uaf漏洞学习
PWN--uaf漏洞 1.uaf漏洞原理 在C语言中,我们通过malloc族函数进行堆块的分配,用free()函数进行堆块的释放.在释放堆块的过程中,如果没有将释放的堆块置空,这时候,就有可能出现us ...
- 双非本科Android开发,如何逆袭拿到大厂 Offer?
从2020年3月18日投出第一份暑期实习简历至今,已经过去400多天.我也尘埃落定,即将去CVTE做Android开发. 休息了很长时间,如今已经能够很平静地回首这段历程,写下这篇文,致敬曾经走过的漫 ...