T1 饥饿的狐狸

解题思路

贪心签到题。

最小值的做法就是对于温度比水小的从大到小吃,然后喝一口水,然后把剩下的从小到大吃掉。

最大值的做法,几乎就是大的挑一个小的挑一个间隔着吃,可以排完序之后双指针扫两边,但是我码了一大堆。。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<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;
int n,ans1,ans2,val,las,s[N];
priority_queue<int> q1;
priority_queue<int,vector<int>,greater<int> > q2;
void solve1()
{
for(int i=1;i<=n;i++)
if(s[i]>=val) q1.push(s[i]);
else q2.push(s[i]);
las=val;
while(!q1.empty()&&!q2.empty())
{
int x=q1.top(),y=q2.top(); q1.pop(); q2.pop();
ans1+=x-las+x-y; las=y;
}
if(q1.empty()&&q2.empty()) return ;
if(!q1.empty())
{
multiset<int> res;
ans1+=val-las;
while(!q1.empty()) res.insert(q1.top()),q1.pop();
while(res.size()>=2)
{
int x=*res.begin(),y=*res.rbegin(); if(y-x<=x-val) break;
res.erase(res.find(x)); res.erase(res.find(y));
ans1+=y-val+y-x;
}
while(res.size()) ans1+=(*res.begin())-val,res.erase(res.begin());
return ;
}
multiset<int> res;
while(!q2.empty()) res.insert(q2.top()),q2.pop();
while(res.size()>=2)
{
int x=*res.begin(),y=*res.rbegin(); if(y-x<=val-y) break;
res.erase(res.find(x)); res.erase(res.find(y));
ans1+=val-x+y-x;
}
while(res.size()) ans1+=val-(*res.begin()),res.erase(res.begin());
}
void solve2()
{
for(int i=1;i<=n;i++)
if(s[i]>=val) q1.push(s[i]);
else q2.push(s[i]);
las=val;
while(!q1.empty()&&!q2.empty())
{
int x=q1.top(),y=q2.top(); q1.pop(); q2.pop();
ans2+=las-y+x-y; las=x;
}
if(q1.empty()&&q2.empty()) return ;
if(!q1.empty())
{
multiset<int> res;
while(!q1.empty()) res.insert(q1.top()),q1.pop();
while(res.size()>=2)
{
int x=*res.begin(),y=*res.rbegin(); if(y-x<=x-val) break;
res.erase(res.find(x)); res.erase(res.find(y));
ans2+=y-val+y-x;
}
while(res.size()) ans2+=(*res.begin())-val,res.erase(res.begin());
return ;
}
multiset<int> res;
ans2+=las-val;
while(!q2.empty()) res.insert(q2.top()),q2.pop();
while(res.size()>=2)
{
int x=*res.begin(),y=*res.rbegin(); if(y-x<=val-y) break;
res.erase(res.find(x)); res.erase(res.find(y));
ans2+=val-x+y-x;
}
while(res.size()) ans2+=val-(*res.begin()),res.erase(res.begin());
}
#undef int
int main()
{
#define int long long
freopen("a.in","r",stdin); freopen("a.out","w",stdout);
n=read(); las=val=read();
for(int i=1;i<=n;i++) s[i]=read();
for(int i=1;i<=n;i++)
if(s[i]<val) q1.push(s[i]);
else if(s[i]>val) q2.push(s[i]);
while(!q1.empty()) ans1+=las-q1.top(),las=q1.top(),q1.pop();
las=val; while(!q2.empty()) ans1+=q2.top()-las,las=q2.top(),q2.pop();
printf("%lld ",ans1); ans1=0; solve1(); solve2();
printf("%lld",max(ans1,ans2));
return 0;
}

T2 保险箱

解题思路

假设密码数组是 \(c\)。

那么就要满足 \(c\) 数组的所有值以及 \(n\) 配上任意的系数相加之后都不可以等于 \(1\sim K-1\) 中的任何一个 \(m_i\)

那么根据裴蜀定理可以得到\(\gcd(n,c_1,c_2...)\nmid m_i\) 。

那么一个比较暴力的做法就出来了:枚举 \(\gcd(n,m_K)\) 的每一个因数判断是否合法,然后选取最大的。

考虑优化一下,对于任何一个 \(m_i\) 而言,它的任何一个因子都是不可以的,那么它在 \(\gcd(n,m_K)\) 的因子这个范围中的因子一定是 \(\gcd(m_i,\gcd(n,m_K))\) 的因数。

于是我们可以先算出来 \(\gcd(n,m_K)\) 的每一个质因子,然后对于每一个 \(\gcd(m_i,\gcd(n,m_K))\) 记忆话搜索就好了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<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=25e4;
int n,g,temp,m,mx,s[N];
vector<int> pri;
set<int> res,in;
inline int gcd(int x,int y){return !y?x:gcd(y,x%y);}
bool check(int x){return res.find(x)==res.end();}
void dfs(int x){if(!check(x))return ;res.insert(x);for(auto y:pri)if(x%y==0)dfs(x/y);}
#undef int
int main()
{
#define int register long long
freopen("b.in","r",stdin); freopen("b.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=m;i++) s[i]=read(); temp=g=gcd(s[m],n);
for(int i=1;i<m;i++) in.insert(gcd(g,s[i]));
for(int i=2;i*i<=temp;i++) if(temp%i==0){pri.push_back(i);while(temp%i==0)temp/=i;}
if(temp!=1) pri.push_back(temp); for(auto it:in) dfs(it);
for(int i=mx=1;i*i<=g;i++,mx++) if(g%i==0&&check(i)) printf("%lld\n",n/i),exit(0);
for(int i=mx-1;i>=1;i--) if(g%(g/i)==0&&check((g/i))) printf("%lld\n",n/(g/i)),exit(0);
return 0;
}

T3 追逐

解题思路

原题,然而当时是水过去的。

一个点的贡献就是它所有和它相邻的节点的权值和减去经过它之前经过节点的权值,直接暴力枚举起点统计可以获得 70pts 。

考虑树形 DP 。 设 \(f_{i,j}\) 表示 \(i\) 节点从他的子树到他丢下 \(i\) 个磁铁的最大值,\(g_{i,j}\) 表示 \(i\) 节点从他到他的子树丢下 \(i\) 个磁铁的最大值。

转移 DP 数组直接考虑是否在这个节点放磁铁就好了,对于答案的统计直接将两个数组拼起来就好了。

由于路径的正反答案是不相同的,所以需要把连边倒过来在计算一遍。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<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=110;
int n,m,ans,all,s[N],cnt[N],f[N][M],g[N][M];
int tot=1,head[N],ver[N<<1],nxt[N<<1];
vector<int> v[N];
void dfs(int x,int fa)
{
for(int i=1;i<=m;i++) f[x][i]=cnt[x],g[x][i]=cnt[x]-s[fa];
for(auto to:v[x])
{
if(to==fa) continue; dfs(to,x);
for(int i=0;i<=m;i++) ans=max(ans,f[x][i]+g[to][m-i]);
for(int i=1;i<=m;i++)
f[x][i]=max(f[x][i],max(f[to][i],f[to][i-1]+cnt[x]-s[to])),
g[x][i]=max(g[x][i],max(g[to][i],g[to][i-1]+cnt[x]-s[fa]));
}
reverse(v[x].begin(),v[x].end());
for(int i=1;i<=m;i++) f[x][i]=cnt[x],g[x][i]=cnt[x]-s[fa];
for(auto to:v[x])
{
if(to==fa) continue;
for(int i=0;i<=m;i++) ans=max(ans,f[x][i]+g[to][m-i]);
for(int i=1;i<=m;i++)
f[x][i]=max(f[x][i],max(f[to][i],f[to][i-1]+cnt[x]-s[to])),
g[x][i]=max(g[x][i],max(g[to][i],g[to][i-1]+cnt[x]-s[fa]));
}
}
#undef int
int main()
{
#define int register long long
freopen("c.in","r",stdin); freopen("c.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++) s[i]=read();
for(int i=1,x,y;i<n;i++)
x=read(),y=read(),
v[x].push_back(y),v[y].push_back(x);
for(int i=1;i<=n;i++) for(auto to:v[i]) cnt[i]+=s[to];
dfs(1,0); printf("%lld",ans);
return 0;
}

T4 字符串

解题思路

最妙的就是关于题意的转化了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
#define ls x<<1
#define rs x<<1|1
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=5e5+10;
int n,q,t;
char ch[N];
struct Node{int len,l,r,sum;};
Node const operator + (Node x,Node y)
{
Node z; z.sum=x.sum+y.sum;
z.len=max(x.r+y.l,max(x.len,y.len));
z.l=max(x.l,y.l+x.sum); z.r=max(y.r,x.r+y.sum);
return z;
}
struct Segment_Tree
{
Node tre[N<<2];
#define push_up(x) tre[x]=tre[ls]+tre[rs]
void build(int x,int l,int r)
{
if(l==r) return t=ch[l]=='C'?1:-1,tre[x]=(Node){t,t,t,t},void();
int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); push_up(x);
}
Node query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x]; int mid=(l+r)>>1;
if(L<=mid&&R>mid) return query(ls,l,mid,L,R)+query(rs,mid+1,r,L,R);
if(L<=mid) return query(ls,l,mid,L,R); return query(rs,mid+1,r,L,R);
}
}T;
#undef int
int main()
{
#define int register long long
freopen("d.in","r",stdin); freopen("d.out","w",stdout);
n=read(); scanf("%s",ch+1); T.build(1,1,n); q=read();
while(q--)
{
int l,r; l=read(); r=read(); Node temp=T.query(1,1,n,l,r);
printf("%lld\n",max(0ll,max(temp.len,max(temp.l,temp.r)))-temp.sum);
}
return 0;
}

NOIP模拟100(多校32)的更多相关文章

  1. NOIP模拟83(多校16)

    前言 CSP之后第一次模拟赛,感觉考的一般. 不得不吐槽多校联测 OJ 上的评测机是真的慢... T1 树上的数 解题思路 感觉自己思维有些固化了,一看题目就感觉是线段树. 考完之后才想起来这玩意直接 ...

  2. NOIP模拟92(多校25)

    前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...

  3. NOIP模拟99(多校31)

    T1 法阵 解题思路 原题3100,张口放 T1(出题人原话) 思维题,合法的情况其实就是上下两个梯形拼起来的样子. 他们的边界都是在 \(i\) 轴上面,但是不能相交. 于是我们可以尝试两者相交的纵 ...

  4. NOIP模拟84(多校17)

    T1 宝藏 解题思路 考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了?? 考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的 ...

  5. NOIP模拟85(多校18)

    前言 好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨). 然后我只知道 T1 的莓,确实挺惨... T1 莓良心 解题思路 首先答案只与 \(w\) 的和有关系,于是问题就 ...

  6. NOIP模拟86(多校19)

    T1 特殊字符串 解题思路 \(f_{i,j}\) 表示前 \(i\) 个字符中结尾为 \(j\) 的最大贡献. 转移枚举当前位置于之前位置结尾的组合加上贡献即可. 对于边界问题,容易发现选择 1 一 ...

  7. NOIP模拟88(多校21)

    前言 对于这套题的总体感觉就是难,然后就是自己很菜... 对于 T1 考试时只会一个最垃圾的背包,考完之后对于思路这一块也不是很顺利,大概这就是薄弱的地方吧. 然后 T2 是比较简单的一道题了,但是考 ...

  8. NOIP模拟96(多校29)

    T1 子集和 解题思路 大概是一个退背包的大白板,然而我考场上想复杂了,竟然还用到了组合数. 但是大概意思是一样的,有数的最小值一定是一个在 \(a\) 数组中存在的数字. 那么我们想办法除去它对应的 ...

  9. noip模拟32[好数学啊]

    noip模拟32 solutions 真是无语子,又没上100,无奈死了 虽然我每次都觉得题很难,但是还是有好多上100的 战神都200多了,好生气啊啊啊 从题开始变难之后,我的时间分配越来越不均匀, ...

  10. NOIP模拟题汇总(加厚版)

    \(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...

随机推荐

  1. 调用App Store Connect Api

    对iOS的证书.描述文件.账号.设备等管理,之前都去苹果开发者中心操作,官网上操作也比较繁杂,想搞一些自动化之类的,更是麻烦,有时候官网都打不开-- 其实苹果还提供里一套API接口,创建证书.创建账号 ...

  2. 浅谈TypeScript对业务可维护性的影响

    前言 笔者认为, TypeScript是服务于业务的, 核心就是提高代码的可维护性. TypeScript是把双刃剑, 如果类型系统使用的不好, 反而会阻碍开发, 甚至最后就变成了anyScript. ...

  3. Crazy Excel:Excel中的泥石流

    Crazy Excel又名:疯狂Excel.是一款PC端的Excel软件工具,该软件支持windows, mac os等主流操作系统. 正如其名,作者在设计之初就加入了一些疯狂的设计,目的是创作出更加 ...

  4. easyx的使用

    本操作集根据B站学习,借鉴: 视频链接:[C/C++/EasyX]学编程,做游戏,小白快速入门图形编程,零基础入门到精通,学习就是这么快乐_哔哩哔哩_bilibili 初始化时要进行的操作: 记得调用 ...

  5. 【编程】C++ 常用容器以及一些应用案例

    介绍一些我常用的C++容器和使用方法,以及使用案例.blog 1 概述 容器(Container)是一个存储其他对象集合的持有者对象.容器以类模板实现,对支持的元素类型有很大的灵活性.容器管理元素的存 ...

  6. 力扣1077(MySQL)-项目员工Ⅲ(中等)

    题目: 写 一个 SQL 查询语句,报告在每一个项目中经验最丰富的雇员是谁.如果出现经验年数相同的情况,请报告所有具有最大经验年数的员工. 查询结果格式在以下示例中: employee_id 为 1 ...

  7. 如何将传统 Web 框架迁移部署到 Serverless 架构?

    简介: 与其说 Serverless 架构是一个新的概念,不如说它是一种全新的思路,一种新的编程范式. 与其说 Serverless 架构是一个新的概念,不如说它是一种全新的思路,一种新的编程范式. ...

  8. sysAK(青囊)系统运维工具集:如何实现高效自动化运维?| 龙蜥技术

    ​简介:What is sysAK.典型工具介绍.开源 3 方面介绍了 sysAK 系统,目前 sysAK 工具集已经在龙蜥社区开源,并且在系统运维 SIG.跟踪诊断 SIG 一起共建,希望大家后期加 ...

  9. [Cryptocurrency] (XMR) Monero GUI 连接远程节点 操作方式

    Monero 官网下载的钱包,在 高级设置 的节点里支持 "本地节点" 和 "远程节点". 本地节点就是同步区块链数据到本地电脑,安全性高,占用空间大. 远程节 ...

  10. Cron Job 表达式解析

    Cron Job 表达式解析 Redisant Toolbox 是一款面向开发者的多合一工具箱,超过30种常用的开发工具:精心设计,快速.高效:离线使用,尊重您的隐私. 目录 Cron Job 表达式 ...