也不能算考得好,虽然这次A了一道题,但主要是那道题太简单了,没啥成就感,而且有好多人都A掉了

除了那一道,其他的加起来一共拿了25pts,这我能咋办,无奈的去改题

整场考试的状态并不是很好啊,不知道是刚放假回来的原因还是昨天晚上没睡好,

考试的时候一直很困,那种睁不开眼的困,然后导致我这次考试前三个题,屁大点的思路都没有

所以还是要保养好精神的,毕竟还有这么多事

所以我下次考试要保持一个好的状态,然后拿最多的分;;;

这次的考题思路极其怪癖,不对,是清奇!!!而且是想不到的清奇

正解::::

T1 星际旅行

题意:一条路径,经过两条边一次,其他的经过两次,求方案数啊

这题迷的不行,这个让求方案数,应该很多吧,然后他还不取模,我就懵圈了,这算啥方案数???

做取模的题做多了,以为方案数都特别大,其实也有小一些的,longlong足以解决这个题

整个就是一大模拟,对我来说,可是我一开始没有看出来咋模拟,

后来听了硕队的讲解,才明白,这是让你去边找欧拉路呐~~~

具体做法就是将所有的路径拆分成两条不同方向的路径,我们就有了2*m条路径,然后我们在这些路径中去掉两条

去掉之后,可以使这个图上的边(拆分后的边),能够一笔画完,(找之前别忘了判断图上的边是否全部联通)

我们考虑欧拉图存在的条件,有两个或者没有连奇数条边的节点,所以根据这个定义,我们可以拆掉的边只有三种情况

  1、任意两个自环(拆自环的话,每个点的边数减少二,不会影响结果)

  2、两个连在同一点上的边(只能这样拆,因为这样那个共同的点拆之后还是偶数,如果任意拆两条边,那么会有四个边数为奇数的点)

  3、任意一个自环和任意一条边(自环不影响,边造成两个奇点)

所以我们在实现的时候,只需要统计有多少自环,有多少边,每个点的度数,用计数原理乘一乘就好了

注意判断是否联通的时候,可以有点没有遍历到,但是边必须都要遍历到

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=100005;
int n,m;
int to[N*2],nxt[N*2],head[N],rp;
int zi,oi,du[N];
ll ans;
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
bool vis[N],edg[N];
int vi;
void dfs(int x,int f){
//cout<<x<<" ";
if(vis[x])return ;
vis[x]=1;
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
//cout<<x<<" "<<y<<" "<<vi<<" ";
//if(y==x)vi++;
//cout<<vi<<endl;
if(y==f)continue;
vi++;
//cout<<x<<" "<<y<<" "<<vi<<endl;
if(vis[y]==0)dfs(y,x);
}
}
signed main(){
scanf("%d%d",&n,&m);
for(re i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
edg[x]=edg[y]=1;
if(x==y){
add_edg(x,y);
zi++;
}
else{
add_edg(x,y);
add_edg(y,x);
oi++;
du[x]++;
du[y]++;
}
}
for(re i=1;i<=n;i++){
dfs(i,0);
if(vi!=0)break;
vis[i]=0;
//cout<<endl;
}
for(re i=1;i<=n;i++){
if(!vis[i]&&edg[i]){
//cout<<i<<endl;
printf("0");return 0;
}
}
ans+=1ll*zi*oi;
ans+=1ll*zi*(zi-1)/2;
//cout<<ans<<endl;
for(re i=1;i<=n;i++){
if(du[i]>1)ans+=1ll*du[i]*(du[i]-1)/2;
}
printf("%lld",ans);
}

T1

T2 砍树

这个题好像比最后一个题还水::::

题意:每隔d天砍一次树,把比期望值高的那部分砍掉,问你在最多砍k长度的情况下,最大的d是多少

所以这个题是个数论题,我竟然没看出来,我瞬间感觉我莫比乌斯专题白学了,竟然连这个题都不会推!!!

气人,所以这个题就是一个简单的推式子,代码写出来25行不到。。。。

我们要求的就是

      $ \sum \limits_{i=1}^{n} \left ( \left \lceil \frac{a_i}{d}  \right \rceil \times d -a_i\right )\le k $

      $ \sum \limits_{i=1}^{n} \left ( \left \lceil \frac{a_i}{d}  \right \rceil \times d \right )-\sum\limits_{i=1}^{n}a_i\le k $

      $ \sum \limits_{i=1}^{n} \left ( \left \lceil \frac{a_i}{d}  \right \rceil \times d \right )\le\sum\limits_{i=1}^{n}a_i+k $

      设C = $ \sum\limits_{i=1}^{n}a_i+k $

      $ \sum \limits_{i=1}^{n} \left \lceil \frac{a_i}{d}  \right \rceil \le \frac{C}{d}  $

      $ \sum \limits_{i=1}^{n} \left \lceil \frac{a_i}{d}  \right \rceil \le \left \lfloor \frac{C}{d}\right \rfloor  $

所以我们就发现后面的式子就是一个关于数论分块的东西

我们就可以用分块去求每个块的左右边界了,不会自己找博客

右侧的每一个块内,一定是右边界最优,而左边,显然随着d的增加他是递减的,所以我们只需要每次判断右边界的取值然后更新答案即可

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=105;
int n;
ll a[N],k,ans;
signed main(){
scanf("%d%lld",&n,&k);
for(re i=1;i<=n;i++)scanf("%lld",&a[i]),k+=a[i];
for(ll l=1,r;l<=k;l=r+1){
r=k/(k/l);
ll tmp=0;
for(re i=1;i<=n;i++){
tmp+=a[i]/r;
if(a[i]%r!=0)tmp++;
}
if(tmp*r<=k)ans=r;
}
printf("%lld",ans);
}

T2

T3 超级树

他把所有的点到他祖先的边都连起来了,这边数多的要爆炸啊

题意:按照上面说的先构建一颗超级树,然后寻找树上的路径条数,要求要遍历每一个点不超过一次,就是说可以不走这个点,单点也算一条路径

这种题,边数如此之多,我们只能往dp的方向去想,不然你去遍历整个图啊,而且你还遍历不完,这咋办,虽然考场上我看到这个题就想困,但是我知道他是个dp

但是这个dp方程也太不正常了,我看题解理解了半个多小时,那我要是自己想得想多久啊,真不知道啥境界才能想出正解啊

设dp[i][j]表示目前i层,并且这个i层的超级树中存在j条不相交的路径的方案数

这个dp含义很难理解,第一维是没问题的,我们看看第二维

简单说就是在这个超级树里,有j条路径,并且这j条路径所覆盖的点没有重复的,就是我们沿着这j条路径走过一遍,每个点只会走一次或者不走

就是j条路径上没有重复的点。。。懂了吧,这dp多么毒瘤,光看定义就知道有多麻烦了;;;;

为什么要这样定义呢,因为我们的转移方程,是有多条路径的方案数想1条转移的,这样才能求出最后的答案

一共有五个转移方程,在转移之前我们一共有三层循环,第一层一定是层数i,第二层是左子树的j,设为l;第三层是右子树的j,设为r;

设num=dp[i][l]*dp[i][r]         就是乘法原理,两颗子树分别有这些情况合并之后自然就是乘起来了。。

      1、我们对这颗树没有任何操作:dp[i+1][l+r]+=num    定义的重要性,根节点此时已经空出来了

      2、我们将目前的根节点与左子树或右子树中的任意一条路径相连:dp[i+1][l+r]+=2*num*(l+r) 我们一共有l+r条路径可以连

            (因为这个根已经和他子树的每一个节点相连了,每条路径都可以连上而且两端是两种情况,所以×2)

      3、我们把根节点自己算作一个单独的路径,就有了:dp[i+1][l+r+1]+=num

      4、我们用根节点分别连接两颗子树中的路径:dp[i+1][l+r-1]+=2*num*l*r

            就是两颗子树中分别有一个路径,然后通过根的链接他变成了一条,左子树l种,右子树r种

      5、我们用根节点去连接某一棵子树内的两条边:dp[i+1][l+r-1]+=num*(l*(l-1)+r*(r-1)) 就是左子树内两个路径变一条,或者右子树内两条变一条

这样我们就搞完了转移方程,然后你发现,这第二维有2^n这么多种情况诶,那你不超时谁超时,

但是这每一次转移都只会将每一个的第二维+1或者-1所以我们只需要n个状态

最后求的是一条路径的方案数,所以答案就是dp[n][1]啦,定义要好好理解

这样我们就可以愉愉快快的写代码啦

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=305;
ll n,mod;
ll dp[N][N];
signed main(){
scanf("%lld%lld",&n,&mod);
dp[1][0]=dp[1][1]=1%mod;
for(re i=1;i<n;i++){
for(re l=0;l<=n;l++){
for(re r=0;r<=n-l;r++){
ll num=dp[i][l]*dp[i][r]%mod;
dp[i+1][l+r]+=num;
dp[i+1][l+r+1]+=num;
dp[i+1][l+r]+=2*num*(l+r);
dp[i+1][l+r-1]+=2*num*l*r;
dp[i+1][l+r-1]+=num*(l*(l-1)+r*(r-1));
dp[i+1][l+r]%=mod;
dp[i+1][l+r+1]%=mod;
dp[i+1][l+r-1]%=mod;
}
}
}
printf("%lld",dp[n][1]);
}

T3

T4 求和

题意:给你一个树,让你求某两个点之间的路径上的所有边权的k次方之和

直接预处理前缀和,树链剖分求lca,然后减一下,这题真水!!!!

#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=310005;
const int mod=998244353;
int n,m;
int to[N*2],nxt[N*2],head[N],rp;
int sum[N][55];
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=1ll*ret*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return ret;
}
int dep[N],siz[N],son[N],top[N],fa[N];
void dfs1(int x,int f){
//cout<<x<<" "<<f<<endl;
for(re i=1;i<=50;i++)sum[x][i]=(1ll*sum[f][i]+ksm(dep[x],i))%mod;
//if(x==130934)cout<<"sb"<<endl;
siz[x]=1;son[x]=0;
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
//if(x==130934)cout<<i<<endl;
if(y==f)return ;
//if(x==130934)cout<<y<<endl;
fa[y]=x;
dep[y]=dep[x]+1;
dfs1(y,x);
siz[x]+=siz[y];
if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
}
}
void dfs2(int x,int f){
top[x]=f;
if(son[x])dfs2(son[x],f);
for(re i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==son[x]||y==fa[x])continue;
dfs2(y,y);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
signed main(){
//int o=time(NULL);
scanf("%d",&n);
for(re i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add_edg(x,y);
add_edg(y,x);
}
//cout<<rp<<" "<<to[rp]<<endl;
dfs1(1,0);
//cout<<"sb"<<endl;
dfs2(1,1);
//cout<<"sb"<<endl;
scanf("%d",&m);
for(re i=1;i<=m;i++){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
int lca=LCA(l,r);
int ans=(1ll*sum[l][k]+sum[r][k]+2ll*mod-sum[lca][k]-sum[fa[lca]][k])%mod;
//if(l>300000||r>300000||k>50)cout<<"sb"<<endl;
printf("%d\n",ans);
}
//cout<<time(NULL)-o<<endl;
}

T4

完结

noip模拟8[星际旅行·砍树·超级树·求和]的更多相关文章

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

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

  2. 7.18 NOIP模拟测试5 星际旅行+砍树+超级树

    T1 星际旅行 题意:n个点,m条边,无重边,有自环,要求经过m-2条边两次,2条边一次,问共有多少种本质不同的方案.本质不同:当且仅当至少存在一条边经过次数不同. 题解:考试的时候理解错题,以为他是 ...

  3. NOIP模拟测试5「星际旅行·砍树·超级树」

    星际旅行 0分 瞬间爆炸. 考试的时候觉得这个题怎么这么难, 打个dp,可以被儿子贡献,可以被父亲贡献,还有自环,叶子节点连边可以贡献,非叶子也可以贡献,自环可以跑一回,自环可以跑两回, 关键是同一子 ...

  4. @省选模拟赛03/16 - T3@ 超级树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...

  5. 【noip模拟赛7】足球比赛 树

    描述 在2009的中国城市足球比赛中,在2^N支队中,有一些队在开赛前宣布了退出比赛.比赛采取的是淘汰赛.比如有4支队伍参加,那么1队和2队比赛,3队和4队赛,然后1队和2队的胜者与3队和4队的胜者争 ...

  6. 【NOIP模拟赛】飞(fly) 数论+树状数组

    树状数组一个被发明以来广为流行的数据结构,基于数组,核心是lowerbit()操作.他向前lowerbit()操作为前缀,向后lowerbit()操作为上辖,我们运用树状数组都是使一个由O(1)变为O ...

  7. 【NOIP模拟】jzoj5233概率博弈(树规)

    Description 小A和小B在玩游戏.这个游戏是这样的: 有一棵

  8. 【2019.7.15 NOIP模拟赛 T2】与非树(nand)(树形DP)

    树形\(DP\) 实际上,这道题应该不是很难. 我们设\(f_{x,i,j}\)表示在以\(x\)为根的子树内,原本应输出\(i\),结果输出了\(j\)的情况数. 转移时,为了方便,我们先考虑与,再 ...

  9. 【NOIP模拟赛】超级树 DP

    这个题我在考试的时候把所有的转移都想全了就是新加一个点时有I.不作为II.自己呆着III.连一个IV.连接两个子树中的两个V连接一个子树中的两个,然而V我并不会转移........ 这个题的正解体现了 ...

随机推荐

  1. 【译】N 皇后问题 – 构造法原理与证明 时间复杂度O(1)

    [原] E.J.Hoffman; J.C.Loessi; R.C.Moore The Johns Hopkins University Applied Physics Laboratory *[译]* ...

  2. 使用docker-compose.yml快速搭建Linux/Mac开发/生产环境

    传送门 点击进入Github,https://github.com/ovim/dockerfiles 简单介绍 Dockerfiles 搭建基础公用环境包,方便使用,支持业务不断的提升而需要一些软件的 ...

  3. UA: Literally Vulnerable靶机

    前言 略有点虎头蛇尾.主要有一步没想通. web打点 nmap -sP 192.168.218.0/24 #发现主机IP 192.168.218.138 #端口扫描 nmap -sV -p- 192. ...

  4. Java_继承

    继承的格式 继承它描述的是两个类之间的关系,如果一个子类继承父类,那么子类可以使用父类非私有的成员. 1 public class 父类{ 2 //成员变量 3 //成员方法 4 } 5 6 publ ...

  5. Jetpack Compose What and Why, 6个问题

    Jetpack Compose What and Why, 6个问题 1.这个技术出现的背景, 初衷, 要达到什么样的目标或是要解决什么样的问题. Jetpack Compose是什么? 它是一个声明 ...

  6. CSS filter 有哪些神奇用途

    背景 基本概念 CSS filter 属性将模糊或颜色偏移等图形效果应用于元素形成滤镜,滤镜通常用于调整图像,背景和边框的渲染.它的值可以为 filter 函数 <filter-function ...

  7. Envoy:离群点检测 outlier detection

    outlier detection 在异常检测领域中,常常需要决定新观察的点是否属于与现有观察点相同的分布(则它称为inlier),或者被认为是不同的(称为outlier).离群是异常的数据,但是不一 ...

  8. [Java] Structs

    背景 基于MVC的WEB框架 在表示层过滤访问请求并处理 步骤 在eclipse中创建Web动态项目 导入相关jar包到WEB-INF/lib 在WEB-INF目录下新建web.xml,配置Filte ...

  9. Python 送你一棵圣诞树

    Python 送你一棵圣诞树 2019-01-02阅读 8800   今天是圣诞节,先祝大家圣诞快乐!??? 有人要说了,圣诞节是耶稣诞生的日子,我又不信基督教,有啥好庆祝的.这你就有所不知了,Pyt ...

  10. 【转载】认识SSD的SATA、mSATA 、PCIe和M.2四种主流接口

    认识SSD的SATA.mSATA .PCIe和M.2四种主流接口 2018-09-25 • 工具 • 评论关闭 认识SSD的SATA.mSATA .PCIe和M.2四种主流接口