愿你和重要的人,在来日重逢。

前言

题目名字起的很随意。。。

这天 Luogu 的运势好像是大凶(忌:打模拟赛,注意报零)。

但是考得还不错,拿到了这么多场模拟赛以来第二三个场上AC。

所以说,我爱大凶

T1 第一题

解题思路

官方题解好像不干人事,直接咕了。。

其实做法都差不多,都是乱搞(反正我是这么干的)。

对于整棵树上的每一个点开一个 multiset,用来维护子树内剩余的每一个士兵的深度。

然后每一次进行子树合并的时候选择深度最小的,但是到当前子树根节点距离的两倍小于根节点深度的点进行利用。

可以这么理解:把整个过程视作最后停留的节点的深度加上其它经过节点到 该节点与停留节点的LCA的距离的二倍(毕竟要下去再上来嘛)

然后就再开一个数组记录上面有来回的时间的贡献。

时间复杂度我不会算,好像是 n 的,但是我的 set 合并的时候都没有启发式合并,感觉最坏的情况会被搞成接近 \(n^2\)。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned 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=1e5+10,M=1e3+10;
int n,ans,fa[N],f[N],dep[N],mx[N];
vector<int> v[N];
multiset<int> s[N];
void add_edge(int x,int y)
{
v[x].push_back(y);
}
void dfs(int x)
{
mx[x]=dep[x];
for(int i=0;i<v[x].size();i++)
{
int to=v[x][i];
if(to==fa[x]) continue;
fa[to]=x;
dep[to]=dep[x]+1;
dfs(to);
mx[x]=max(mx[x],mx[to]);
}
}
void merge(multiset<int> &a,multiset<int> &b)
{
for(auto it=b.begin();it!=b.end();it++)
a.insert((*it)+1);
}
bool comp(int x,int y)
{
return mx[x]<mx[y];
}
void solve(int x)
{
bool flag=false;
sort(v[x].begin(),v[x].end(),comp);
for(int i=0;i<v[x].size();i++)
{
int to=v[x][i];
if(to==fa[x]) continue;
flag=true; solve(to);
for(auto it=s[x].begin();it!=s[x].end();it++)
{
if((*it)>=dep[x]||!s[to].size()) break;
auto it2=(--s[to].end());
if((*it2)+1<(*it)) break;
f[x]+=(*it)*2;
s[to].erase(it2);
s[x].erase(it);
s[x].insert((*it2)+1);
}
f[x]+=f[to];
merge(s[x],s[to]);
}
if(!flag) s[x].insert(0);
}
signed main()
{
n=read();
for(int i=1,x,y;i<n;i++)
{
x=read(); y=read();
add_edge(x,y);
add_edge(y,x);
}
dfs(1);
solve(1);
for(auto it=s[1].begin();it!=s[1].end();it++)
ans+=(*it);
printf("%lld",ans+f[1]);
return 0;
}

T2 第二题

解题思路

做法依旧非常暴力。(但是好像别的做法也可以被极端数据卡掉,比如n=1,m=1e5

一眼看出是二分答案。

二分最小的差值,判断是否可以用 \(\le k\) 的步数实现。

用一种类似于 SPFA 的方法实现判断。

为了保证每一个点都被扫到,先把所有的点都放到队列里面。

然后扫描每一个点周围的点的最大值,看看差值是否符合条件,不符合的话就更改并计入贡献。

接下来再次扫描周围的六个点,对于不合法的更改计入贡献,对于更改过但是不再队列里的入队。

最后把贡献和与 k 比较就好了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned 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=5e3+10,M=1e5+10,INF=1e18;
int n,m,K,minn=INF,maxn;
int d1[10]={0,0,0,1,-1,1,-1};
int d2[10]={0,1,-1,0,0,-1,1};
bool vis[M];
vector<int> s[M],p[M];
pair<int,int> id;
struct Queue
{
int l,r;
pair<int,int> num[M<<2];
bool empty(){return l>r;}
pair<int,int> front(){return num[l];}
void clear(){l=1;r=0;}
void push(pair<int,int> temp){num[++r]=temp;}
void pop(){l++;};
}q;
int pos(int x,int y)
{
return (x-1)*m+y;
}
bool check(int mid)
{
memset(vis,true,sizeof(vis));
int sum=0; q.clear();
for(int i=1;i<=n;i++)
{
p[i]=s[i];
for(int j=1;j<=m;j++)
q.push(make_pair(i,j));
}
while(!q.empty())
{
int x=q.front().first,y=q.front().second;
q.pop(); vis[pos(x,y)]=false;
int maxn=0;
for(int i=1;i<=6;i++)
{
int x2=x+d1[i],y2=y+d2[i];
if(x2<=0||y2<=0||x2>n||y2>m) continue;
maxn=max(maxn,p[x2][y2]);
}
if(maxn-p[x][y]>mid)
{
sum+=maxn-p[x][y]-mid;
p[x][y]=maxn-mid;
}
if(sum>K) return false;
for(int i=1;i<=6;i++)
{
int x2=x+d1[i],y2=y+d2[i];
if(x2<=0||y2<=0||x2>n||y2>m) continue;
if(abs(p[x][y]-p[x2][y2])>mid)
{
sum+=p[x][y]-p[x2][y2]-mid;
p[x2][y2]=p[x][y]-mid;
if(!vis[pos(x2,y2)]) q.push(make_pair(x2,y2)),vis[pos(x2,y2)]=true;
}
}
if(sum>K) return false;
}
return sum<=K;
}
signed main()
{
n=read(); m=read(); K=read();
for(int i=1;i<=n;i++) s[i].push_back(0);
for(int i=1;i<=n;i++)
for(int j=1,x;j<=m;j++)
{
x=read();
s[i].push_back(x);
minn=min(minn,s[i][j]);
if(maxn<=s[i][j]) id=make_pair(i,j);
maxn=max(maxn,s[i][j]);
}
int l=0,r=maxn-minn,ans=maxn-minn;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)){r=mid-1;ans=mid;}
else l=mid+1;
}
printf("%lld",ans);
return 0;
}

T3 第三题

解题思路

看出来是数位 DP 了,奈何我太弱,不会。。

\(f_{i,j,l,r}\) 表示当先考虑到第 i 位,已经填上了 j 个 1,是否压紧上下界。

储存两个值:当前状态的数字个数,以及所有数字的总和。

为了方便我们计算 a 到 INF 以及 b 到 INF 的值,最后减一下就好了。

先记忆化DFS一遍算出限制内合法的个数。

然后就类似于查询排名,根据第一维的数字个数求出合法的数字总和。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned 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 Lg=30;
struct Node
{
int x,y;
}f[Lg+10][Lg+10][2][2];
int T,li,ri,a,b;
Node dfs_unlim(int i,int j,bool l,bool r)
{
if(i<0||j<0) return (Node){0ll,0ll};
if(~f[i][j][l][r].x) return f[i][j][l][r];
int lim1=l&(li>>i),lim2=r&(!((ri>>i)&1));
Node ans1=(Node){0ll,0ll},ans2=(Node){0ll,0ll};
if(!lim1) ans1=dfs_unlim(i-1,j,(!((li>>i)&1))&l,(!((ri>>i)&1))&r);
if(!lim2) ans2=dfs_unlim(i-1,j-1,(li>>i)&l,(ri>>i)&r);
return f[i][j][l][r]=(Node){ans1.x+ans2.x,ans1.y+ans2.y+ans2.x*(1<<i)};
}
Node dfs_lim(int i,int j,bool l,bool r,int rk)
{
if(i<0||j<0||!rk) return (Node){0ll,0ll};
if(~f[i][j][l][r].x&&f[i][j][l][r].x<=rk) return f[i][j][l][r];
int lim1=l&(li>>i),lim2=r&(!((ri>>i)&1));
Node ans1=(Node){0ll,0ll},ans2=(Node){0ll,0ll};
if(!lim1) ans1=dfs_lim(i-1,j,(!((li>>i)&1))&l,(!((ri>>i)&1))&r,rk);
if(!lim2) ans2=dfs_lim(i-1,j-1,(li>>i)&l,(ri>>i)&r,rk-ans1.x);
return (Node){ans1.x+ans2.x,ans1.y+ans2.y+ans2.x*(1<<i)};
}
int work(int rk)
{
int sum=0;
for(int i=0;i<=Lg;i++)
if(rk>=f[Lg][i][1][1].x)
{
if(!(~f[Lg][i][1][1].x)) continue;
rk-=f[Lg][i][1][1].x;
sum+=f[Lg][i][1][1].y;
}
else
{
sum+=dfs_lim(Lg,i,1,1,rk).y;
break;
}
return sum;
}
int solve()
{
li=read(); ri=read(); b=read(); a=read();
a=ri-li+1-a+1; b=ri-li+1-b+1;
memset(f,-1,sizeof(f));
f[0][0][0][0]=f[0][0][0][1]=(Node){1ll,0ll};
f[0][0][1][0]=f[0][0][1][1]=(Node){!(li&1),0ll};
f[0][1][0][0]=f[0][1][1][0]=(Node){1ll,1ll};
f[0][1][0][1]=f[0][1][1][1]=(Node){ri&1,ri&1};
for(int i=1;i<=Lg;i++)
f[Lg][i][1][1]=dfs_unlim(Lg,i,1,1);
return work(b)-work(a-1);
}
signed main()
{
T=read();
while(T--) printf("%lld\n",solve());
return 0;
}

T4 第四题

解题思路

题面描述的不太清楚,我说一下自己的理解。

对于一个序列,保证每一位都是在 \([1,n]\) 范围内的,并且前 i 位的最大值等于 前 i-1 位的最大值,或者只比它多 1 。(这个序列并不一定是 \(1\sim n\) 的排列)

\(f_{i,j}\) 表示选择 i 个数最大的数字为 j 的方案数。

\(g_{i,j}\) 表示在最大值为 j 的序列后再选择 i 个数的方案数。

这两个方程可以互补求出整个序列的值。

因为\(k^2=C_{k}^{2}\times 2 + k\),所以每一种方案的贡献是 1+后面再选一个 x 的方案数 \(\times 2\)

可以的得出在第 i 个位置的 x 的贡献就是:

\[\sum\limits_{y\ge x}f_{i-1,y}\times(g_{n-i,y}\times 2\times (n-i)\times g_{n-i-1,y})
\]
\[+f_{i-1,x-1}\times(g_{n-i,x}\times 2\times (n-i)\times g_{n-i-1,x})
\]

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned 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=3e3+10;
int n,mod,f[N][N],g[N][N],s[N][N],ans[N];
void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
signed main()
{
n=read(); mod=read();
f[0][0]=f[1][1]=1;
for(int i=1;i<=n;i++)
g[0][i]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++)
add(f[i][j],(f[i-1][j]*j%mod+f[i-1][j-1])%mod);
for(int i=1;i<=n;i++)
for(int j=1;j<=n-i;j++)
add(g[i][j],(g[i-1][j]*j%mod+g[i-1][j+1])%mod);
for(int i=1;i<=n;i++)
for(int j=i;j>=1;j--)
add(s[i][j],(f[i-1][j]*(g[n-i][j]+2*(n-i)*g[n-i-1][j]%mod)%mod+s[i][j+1])%mod);
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
add(ans[j],(s[i][j]+f[i-1][j-1]*(g[n-i][j]+2*(n-i)*g[n-i-1][j]%mod))%mod);
for(int i=1;i<=n;i++)
printf("%lld ",(ans[i]+mod)%mod);
return 0;
}

改题记录

8.18考试总结(NOIP模拟43)[第一题·第二题·第三题·第四题]的更多相关文章

  1. 8.18考试总结[NOIP模拟43]

    又挂了$80$ 好气哦,但要保持优雅.(草 T1 地衣体 小小的贪心:每次肯定从深度较小的点向深度较大的点转移更优. 模拟一下,把边按链接点的子树最大深度排序,发现实际上只有上一个遍历到的点是对当前考 ...

  2. [考试总结]noip模拟43

    这个题目出的还是很偷懒.... 第一题...第二题...第三题...四.... 好吧... 这几次考得都有些问题,似乎可能是有些疲惫,脑袋也是转不太动,考完总觉得自己是能力的问题,但是改一分钟之后会发 ...

  3. 团队作业4——第一次项目冲刺(Alpha版本)第一天+第二天+第三天+第四天+第五天+第六天+第七天

    冲刺第一天 一.Daily Scrum Meeting照片 二.每个人的工作 1.今天计划完成的任务 GUI.计时功能.题目生成 2.工作中遇到的困难 刚开始在计时功能模块只能做到秒位,经过查询资料后 ...

  4. 2021.10.18考试总结[NOIP模拟76]

    T1 洛希极限 不难发现每个点肯定是被它上一行或上一列的点转移.可以预处理出每个点上一行,上一列最远的能转移到它的点,然后单调队列优化. 预处理稍显ex.可以用并查集维护一个链表,记录当前点之后第一个 ...

  5. 2021.9.18考试总结[NOIP模拟56]

    T1 爆零 贪心地想,肯定要先走完整个子树再走下一个,且要尽量晚地走深度大的叶子.所以对每个点的儿子以子树树高为关键字排序$DFS$即可. 也可$DP$. $code:$ T1 #include< ...

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

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

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

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

  8. NOI.AC NOIP模拟赛 第一场 补记

    NOI.AC NOIP模拟赛 第一场 补记 candy 题目大意: 有两个超市,每个超市有\(n(n\le10^5)\)个糖,每个糖\(W\)元.每颗糖有一个愉悦度,其中,第一家商店中的第\(i\)颗 ...

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

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

  10. 编程语言性能游戏排行榜,C/C++第一ATS第二JAVA第三

    编程语言性能游戏排行榜,C/C++第一ATS第二JAVA第三 编程语言性能游戏排行榜,C/C++第一ATS第二JAVA第三

随机推荐

  1. js 检查对象是否没有字段

    前言 我以前遇到的一个问题. var object={}; if(object=={}) { } 在这里我遇到了问题,一直是lese状态. 后来想想其实也是自己犯了一个很严重的问题,这两个不是同一个对 ...

  2. html 渲染原理

    渲染 从上面这个图上,我们可以看到,浏览器渲染过程如下: 解析HTML,生成DOM树,解析CSS,生成CSSOM树 将DOM树和CSSOM树结合,生成渲染树(Render Tree) Layout(回 ...

  3. 禅道统计BUG解决时长过滤节假日和跨天问题

    之前发过禅道的各种数据统计报表,使用过程中优化了一些,反映最多的是项目bug的解决时长统计问题: 1.比如当天下班左右提交的bug,研发第二天来解决,晚上这段时间应该去掉,不应计算在内 2.节假日.周 ...

  4. 【Oracle】使用like的时候遇到的问题

    [Oracle]使用like的时候遇到的问题 like语句其中的%就代表着一个零或者多个字符,_代表一个字符,%与_可以同时使用 name想查询以'_'结尾的字符 用这个语句就会有问题 select ...

  5. 力扣645(java)-错误的集合(简单)

    题目: 集合 s 包含从 1 到 n 的整数.不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 . 给定一个数组 nu ...

  6. 成中集团线下IDC迁移上云

    阿里云根据成中集团业务场景入手,提供了上云方案和迁移建议,利用这套架构,保障了公司数据的安全性并且满足了公司对于备份机制的建立的基本诉求,并且降低了业务出现中断的风险. 公司介绍 成中简介: 我们公司 ...

  7. 阿里云 EDAS 3.0 助力唱鸭提升微服务幸福感

    简介: EDAS 3.0 提供的微服务治理,很好的支持了唱鸭 APP 实现微服务应用的发布.监控.管理等日常业务场景.作为运维侧的重要平台和开框架的提供者,EDAS 3.0 帮助用户可以更专注业务.微 ...

  8. 阿里云 Serverless 助力企业全面拥抱云原生

    ​简介:相信随着云计算的发展,Serverless 将成为云时代默认的计算范式,越来越多的企业客户将会采用这个技术. 作者:洛浩 Serverless 应用引擎的组件架构 最早的时候,大家设计软件一般 ...

  9. 应对 Job 场景,Serverless 如何帮助企业便捷上云

    简介:函数计算作为事件驱动的全托管计算服务,其执行模式天生就与这类 Job 场景非常契合,对上述痛点进行了全方面的支持,助力"任务"的无服务器上云. 作者:冯一博 任务(Jobs) ...

  10. [Blockchain] Cosmos Starport 地址前缀的变更方式

    # 在新的区块链上修改 starport app github.com/hello/planet --address-prefix your_new_prefix # 在已存在的区块链上修改 `app ...