也不能算考得好,虽然这次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. HDU - 1789 Doing Homework again(贪心) ~~~学了一波sort对结构体排序

    题目中因为天数和分数是对应的,所以我们使用一个结构体来存分数和截止如期. 一开始做这道题的时候,很自然的就想到对天数排序,然后天数一样的分数从大到小排序,最后WA了之后才发现没有做到"舍小取 ...

  2. SQL注入:Sqlmap初体验

    目录 sqlmap 安装 查看帮助文档 中文文档 直连数据库 服务型数据库(mysql) 文件型数据库(sqlite) 初级实战 1. 扫描注入点 2. 根据注入点查到全部数据库 --dbs 3. 根 ...

  3. React中diff算法的理解

    React中diff算法的理解 diff算法用来计算出Virtual DOM中改变的部分,然后针对该部分进行DOM操作,而不用重新渲染整个页面,渲染整个DOM结构的过程中开销是很大的,需要浏览器对DO ...

  4. win10下卸载ubuntu的合理操作

    这里不推荐使用第三方软件,因为可能会被植入病毒,而且windows自带的命令行工具足以完成任务! win10系统自带的一个命令行工具--diskpart 在cmd中输入"diskpart&q ...

  5. JAVA基础——变量、常量

    变量 java中,变量时最基本的存储单元,其要素包括变量名,变量类型和作用域. 注意事项: 每个变量都有类型,类型可以是基本类型,也可以是引用类型. 变量名必须是合法的标识符 变量声明时一条完整的语句 ...

  6. 【zombie】如何查看并杀死僵尸进程?

    [zombie]如何查看并杀死僵尸进程? 赏金Micheal关注 2019.03.31 19:40:15字数 1,016阅读 4,373 僵尸进程定义 In UNIX System terminolo ...

  7. 【转载】搭建本地yum源:以下是以centos7为例子

    搭建本地yum源:以下是以centos7为例子  1)首先需要安装 createrepo(需要一个可以使用源的机器,可以访问互联网)安装方法可以使用yum安装epel源 1 yum -y instal ...

  8. k8s创建资源的两种方式及DaemonSet应用(5)

    一.创建方式分类 Kubernetes 支持两种方式创建资源: (1)用 kubectl 命令直接创建,比如: kubectl run httpd-app --image=reg.yunwei.com ...

  9. 。 (有些情况下通过 lsof(8) 或 fuser(1) 可以 找到有关使用该设备的进程的有用信息)

    umount时目标忙解决办法 标签(空格分隔): ceph ceph运维 osd 在删除osd后umount时,始终无法umonut,可以通过fuser查看设备被哪个进程占用,之后杀死进程,就可以顺利 ...

  10. (xxx) is not defined at HTMLInputElement.onblur(Day_27)

    错误: 这个报错我当时是卡了很久,方法是肯定没有问题的,但js所有的事件都失效了. 解决方案: 1.检查js命名是否有误,若外部引用js文件,尽量使用全小写命名,遵守js命名规范. 2.若还不行,请将 ...