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

前言

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

这天 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. leetcode:1380. 矩阵中的幸运数

    1380. 矩阵中的幸运数 给你一个 m * n 的矩阵,矩阵中的数字 各不相同 .请你按 任意 顺序返回矩阵中的所有幸运数. 幸运数是指矩阵中满足同时下列两个条件的元素: 在同一行的所有元素中最小 ...

  2. D365增加Model reference,解决does not designate a class or table编译错误问题

    当我们导入基础数据时,需要创建一些基本的Emplyee信息,当引用到HcmHireNewWorkerContract和HcmWorkerTransition时,提示如下错误: 'HcmHireNewW ...

  3. CF1535F String Distance

    \(CF1535F\ \ String\ Distance\) 题意 给 \(n\) 个长度均为 \(len\) 的字符串 \(T_1,T_2,\dots T_n\),定义 \(f(a,b)\) 为将 ...

  4. 从“预见”到“遇见” | SAE 引领应用步入 Serverless 全托管新时代

    简介: 阿里云 Serverless 应用引擎(简称 SAE)初衷是让客户不改任何代码,不改变应用部署方式,就可以享受到微服务+K8s+Serverless 的完整体验,开箱即用免运维.作为业界首款面 ...

  5. “让专业的人做专业的事”,畅捷通与阿里云的云原生故事 | 云原生 Talk

    简介: 如何借助阿里云强大的 IaaS 和 PaaS 能力去构建新一代的 SaaS 企业应用,从而给客户提供更好.更强的服务,这是畅捷通一直在思考和实践的方向.最终,畅捷通选定阿里云企业级分布式应用服 ...

  6. Dubbo-Admin 正式支持 3.0 服务治理

    ​简介:Dubbo 相信大家并不陌生,是一款微服务开发框架,它提供了 RPC 通信与微服务治理两大关键能力.大家在日常开发中更多使用的是 Dubbo 提供的 RPC 通信这一部分能力,而对其提供的服务 ...

  7. [FAQ] eggjs/egg 自定义 favicon.ico

      从  egg 项目配置里找到这一段代码: https://github.com/eggjs/egg/blob/master/config/config.default.js#L205C21-L20 ...

  8. dotnet 读 WPF 源代码笔记 GlyphRun 的 DeviceFontName 的功能是什么

    在 WPF 里面的 GlyphRun 里,有一个令人迷惑的 DeviceFontName 属性,似乎给这个属性传入什么值,结果都不会有变更.通过阅读源代码,可以了解到,这是一个没什么用途的属性.本文将 ...

  9. WPF 已知问题 BitmapDecoder.Create 不支持传入 Asynchronous 的文件流

    这是在 GitHub 上有小伙伴报的问题,在 WPF 中,不支持调用 BitmapDecoder.Create 方法,传入的 FileStream 是配置了 FileOptions.Asynchron ...

  10. vue项目上线前优化(路由懒加载的使用,外部CDN的使用)

    引 当使用vue做完项目后,接下来当然是要进行线上部署了.但是在上线之前还是可以做很多方面优化的,可以让项目上线后的体验更加哦. 若是使用了vue-cli的话,可以从面板界面直观的看到各项数据,控制台 ...