打开比赛第一眼——超级树?

点开——原题

百感交集……

欣喜于发现是半年前做过两遍的原题

紧张于如果A不了比较尴尬

绝望于发现根本不会做了

瞟了一眼t1,瞅了一眼t2,嗯……开始搞t3

10分钟打完暴力,开始dp退柿子。然而一个半小时过去了,发现经过一番挫折才终于想起来那个阴间的状态

上了个厕所,看了下表不早了,得开始写前面的了,好恋恋不舍~

再看t2,10分钟打了个很不确定的二分

再看t1,20分钟推了个没有证明的结论

写完都交了

看了下表大概九点半多了,感觉两个小时一事无成,但还是铁下心又回去推t3。

写了好几草稿纸的柿子,手模 \(n=3\) 的情况,老是差那么一点点……

听见隔壁大佬自言自语说t1好难处理,估计是挂了

上厕所看见好多人都在看t2,估计二分是伪了

心里想着算了吧,t3没A就没A吧,估计好多人也忘了

但一想要是现在停下来两个多小时努力就白费了

又一想这题上次也是我讲的肯定是会做哒

再一想只要A掉这道题排名肯定也不会差

于是一直推一直推直到结束也没弄出来……

于是得到了史无前例的糟糕成绩……

题解


好了好了,先回归正题~

A. 星级旅行

首先,要看出这道题的本质是求欧拉路。相当于将每条边复制一下,这时每个点的度数都成为偶数,然后去掉两条边使得整个图有欧拉路

由于这道题里光明正大地说有自环,记自环数量为 \(tot\),于是可以分为三种情况:

  1. 删除两个自环,这时这两个点的度数都减少2(或者一个点减少4),满足题意,答案为 \(C_{tot}^2\)
  2. 删除一个自环和一条边,这时边两端的点度数减少1,成为奇数度点,分别成为起点和终点,答案为 \(tot*(m-tot)\)
  3. 删除两条边,这时有特殊要求是这两条边有一个公共的端点,产生两个奇数度点,此时答案为 \(\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的更多相关文章

  1. NOIP模拟测试18(T3待更新)

    T1: 直接模拟,详见代码注释. 复杂度$O(NM)$. Code: #include<iostream> #include<cstdio> #include<vecto ...

  2. 2019.8.12 NOIP模拟测试18 反思总结

    写个博客总是符合要求的对吧 回来以后第一次悄悄参加考试,昨天全程围观… 然后喜提爆炸120分wwwwwwwww T1用了全机房最慢的写法,导致改掉死循环T掉的一个点以后还是死活过不了最后一个点.T2全 ...

  3. NOIP模拟测试18「引子·可爱宝贝精灵·相互再归的鹅妈妈」

    待补 引子 题解 大模拟,注意细节 代码1 #include<bits/stdc++.h> using namespace std; int n,m;char a[1005][1005]; ...

  4. NOIP模拟测试17&18

    NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...

  5. 「题解」NOIP模拟测试题解乱写II(36)

    毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...

  6. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  7. 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

    2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...

  8. 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)

    2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...

  9. NOIP模拟测试1(2017081501)

    好,今天是cgg第一次举行模拟测试,希望各位支持. 时间限制:2小时 题目链接: 题目一:水得都没名字了 题目二:车站 题目三:选数 不要觉得2小时太少,我的题目很良心,都很简单. 答案可以在模拟测试 ...

随机推荐

  1. phpunit 远程代码执行漏洞(CVE-2017-9841)

    影响版本 4.8.19 ~ 4.8.27 5.0.10 ~ 5.6.2 访问进行抓包 http://192.168.49.2:8080/vendor/phpunit/phpunit/src/Util/ ...

  2. dio框架访问云函数参数传递问题(以腾讯云中的云函数为例子)第一部

    dd云函数其实比较普及,这里以腾讯云的云函数为例,传递参数完成简单的账号注册. 一.第一步先注册腾讯云账号,这里不过多阐述,接着点击 控制台 进入开发者界面.(注意提前进行实名认证) 二.开发者界面如 ...

  3. 单片机学习(一)项目的建立和vscode代码编辑环境的设置

    目录 Keil项目的建立 使用vscode进行开发 工欲善其事必先利其器,因此我们先搭建一个比较舒服的开发环境. Keil项目的建立 打开Keil软件点击Project/New uVision Pro ...

  4. postman之断言

    1 (状态码断言)和(返回内容断言)

  5. Rip CD on Ubuntu

    用Mint自带的banshee可以把CD转换为ogg文件,[Media -> Import Media],然后选择Audio CD,但只能转换为ogg格式,好像不能自动获取ID3标签:比较好的方 ...

  6. git只提交部分修改的文件(提交指定文件)

    在我们的项目中,经常会在本地编译一些代码,还未写完,测试那边来告诉你要改改某个文件的bug,非常着急,此时改完了,提交的时候,自己还在编译的代码并不想提交,此时,你可以利用git这些指令帮助你! 1/ ...

  7. PXE高效批量装机

    目录 一.PXE概述 二.PXE的优点 三.搭建PXE的前提 四.搭建PXE远程安装服务器 4.1.安装并启用TFTP服务 4.2.安装dhcp服务 4.3.准备linux内核.初始化镜像文件 4.3 ...

  8. 爬虫实践二--豆瓣top250电影

    import requests def get_movies(): headers={ 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...

  9. 【原创】利用“进程注入”实现无文件不死webshell

    引子 上周末,一个好兄弟找我说一个很重要的目标shell丢了,这个shell之前是通过一个S2代码执行的漏洞拿到的,现在漏洞还在,不过web目录全部不可写,问我有没有办法搞个webshell继续做内网 ...

  10. XXXMapper.xml中嵌套查询

    XXXMapper.xml中嵌套查询 <resultMap id="LiveUserNocticeMap" type="com.fxkj.common.vo.Liv ...