前言

由于太菜了,多校26 只改出来了 T1 ,于是直接并在一起写啦~~~。

T0 NOIP 2018

解题思路

第一次考场上面写三分,然而我并不知道三分无法处理不是严格单峰的情况,但凡有一个平台都不行??

我们的贪心策略一定是尽量让我们选择的两个物品的值尽量接近,二分最后选择的一个价值,然后判断是否可行。

需要特判一下只选择一个的情况,以及两个个数相差一的情况,实现细节有一点多。。

code

#include<bits/stdc++.h>
#define int __int128
#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;
}
inline void write(int x)
{
#define sta number
int sta[70],top=0; if(x<0) putchar('-'),x=~(x-1);
while(x) sta[++top]=x%10,x/=10; if(!top) sta[++top]=0;
while(top) putchar(sta[top--]+'0'); putchar('\n');
#undef sta
}
int q,n,a,b,c,d,ans;
inline int g(int x,int y,int pos){return x*pos+y*(pos-1)*pos/2;}
inline long long g2(long long x,long long y,long long pos){return x*pos+y*(pos-1)*pos/2;}
inline int work(int x,int y){return (x-a)/b+(y-c)/d+2;}
bool check(int x)
{
int t1=max((int)0,(x-a)/b+1),t2=max((int)0,(x-c)/d+1),temp=g(a,b,t1)+g(c,d,t2);
if(temp<=n) return true;
if(t1>=1&&g(a,b,t1-1)+g(c,d,t2)<=n) ans=max(ans,t1+t2-1);
else if(t2>=1&&g(a,b,t1)+g(c,d,t2-1)<=n) ans=max(ans,t1+t2-1);
return false;
}
void sol(int x,int y)
{
int l=0,r=n,temp=-1;
while(l<=r)
{
int mid=(l+r)>>1,jud=false;
jud|=x*mid>n; jud|=g(x,y,mid)!=g2(x,y,mid);
jud|=g(x,y,mid)>n;
if(!jud) l=mid+1,temp=mid;
else r=mid-1;
}
ans=max(ans,temp);
}
void solve()
{
a=read(); b=read(); c=read(); d=read(); n=read();
int l=0,r=n,temp=-1; ans=0; sol(a,b); sol(c,d);
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) l=mid+1,temp=mid;
else r=mid-1;
}
if(~temp) ans=max(ans,work(temp,temp)); write(ans);
}
#undef int
int main()
{
#define int long long
freopen("money.in","r",stdin); freopen("money.out","w",stdout);
q=read(); while(q--) solve();
return 0;
}

T1 开挂

解题思路

一个直接的想法就是给 \(b\) 排序然后给需要移动步数多的点较小的 \(b\) 。

我们肯定是要把一些重复的值填在一些空闲的值域里面,那么为了让答案尽量小,我们要让移动步数尽量不平均。

于是可以先把所有需要安排位置的数字放入一个栈,数值从栈低到栈顶单调不降。

对于一个空闲的值域,优先选择栈顶元素也就是较大的元素放入就好了..

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=1e6+10,INF=1e18;
int n,p,cnt,all,top,sta[N],a[N],b[N],c[N],s[N];
pair<int,int> res[N];
ull ans;
#undef int
int main()
{
#define int long long
freopen("openhook.in","r",stdin); freopen("openhook.out","w",stdout);
n=read(); a[n+1]=INF;
for(int i=1;i<=n;i++) a[i]=read(); sort(a+1,a+n+1);
for(int i=1;i<=n;i++) b[i]=read(); sort(b+1,b+n+1);
for(int i=1,len=1;i<=n;i++)
if(a[i]==a[i+1]) s[++all]=a[i];
else if(a[i+1]!=a[i]+1)res[++cnt]=make_pair(a[i]+1,a[i+1]-1);
for(int i=1,pos=0;i<=cnt;i++)
{
if(s[pos]>res[i].second) continue;
while(pos<all&&s[pos+1]<res[i].first) sta[++top]=s[++pos];
for(int j=res[i].first;j<=res[i].second&&top;j++)
{
c[++p]=j-sta[top--];
while(pos<all&&s[pos+1]<j+1) sta[++top]=s[++pos];
}
}
sort(c+1,c+n+1,greater<int>());
for(int i=1;i<=n;i++) ans+=c[i]*b[i];
printf("%llu",ans);
return 0;
}

T2 叁仟柒佰万

解题思路

子段中 \(mex\) 的值一定是全局的 \(mex\) 值。

设 \(f_i\) 表示前 \(i\) 的数字划分子段 \(mex\) 等于 \(1\sim n\) 的 \(mex\) 值的方案数。

假设全局 \(mex\) 值为 \(K\) ,那么转移方程就是 \(f_i=\sum\limits_{j=1}^{i-1}f_{j-1}\times[mex_{[i,j]}=K]\)

我们可以维护一个指针 \(pos\) 表示 \([1,pos]\) 的 \(mex\) 值都是 \(K\) 这个指针显然只会右移,同时在维护一下当前 \([pos,i]\) 区间的 \(mex\) 值用来维护。

实现细节稍多。

code

#include<bits/stdc++.h>
#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=37e6+10,Num=262143,mod=1e9+7;
int T,n,pos,num,ans,X,Y,s[N],pre[N],cnt[N],mex;
bool vis[N];
void solve()
{
n=read(); ans=vis[0]=0; pos=num=mex=0; pre[0]=1; s[0]=N-1;
if(n!=N-10) for(int i=1;i<=n;i++) s[i]=read(),vis[i]=false;
else{X=read();Y=read();for(int i=2;i<=n;i++)s[i]=(1ll*s[i-1]*X+Y+i)&Num;}
for(int i=1;i<=n;i++) vis[s[i]]=true; while(vis[mex]) mex++;
if(n!=N-10) for(int i=0;i<=n;i++) cnt[i]=0;
for(int i=1;i<=n;i++)
{
int las=-1; cnt[s[i]]++; while(cnt[num]) num++;
while(num>=mex&&pos<=i){cnt[s[pos]]--; if(!cnt[s[pos]]&&s[pos]<num) las=num,num=s[pos]; pos++;}
if(~las) pos--,cnt[s[pos]]++,num=las; pre[i]=pre[i-1]; if(pos>=1) pre[i]=(pre[i]+pre[pos-1])%mod;
}
printf("%d\n",(pre[n]-pre[n-1]+mod)%mod);
}
int main()
{
freopen("clods.in","r",stdin); freopen("clods.out","w",stdout);
T=read(); while(T--) solve();
return 0;
}

T3 超级加倍

解题思路

有一种 Kruskal 重构树的感觉(好像从严格意义上来讲并不是),更多的开始能使一种笛卡尔树的东西吧。。

按照编号从大到小建树为 T1 从小到大建树为 T2 。

那么这两棵树的性质就是: 满足任意两点 x, y 在 T1 中的 lca 是路径最小值,在 T2 中是路径最大值。

那么符合条件的点对 \((x,y)\) 就需要满足 x 在 T1 中是 y 的祖先,y 在 T2 中是 x 的祖先。

直接在一棵树的 DFS 序上开树状数组,然后 DFS 另一棵树记录祖先的信息查询就好了。

code

#include<bits/stdc++.h>
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=2e6+10;
int n,dfn[N],siz[N];
long long ans;
vector<int> v[N];
struct Edge
{
int tot=1,tim,head[N],ver[N<<1],nxt[N<<1];
void add(int x,int y){ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs(int x){dfn[x]=++tim;siz[x]=1;for(int i=head[x];i;i=nxt[i])dfs(ver[i]),siz[x]+=siz[ver[i]];}
}e1,e2;
struct DSU
{
int fa[N];
void init(){for(int i=1;i<=n;i++)fa[i]=i;}
int find(int x){if(fa[x]==x) return x;return fa[x]=find(fa[x]);}
void merge(int x,int y){fa[find(x)]=find(y);}
}D1,D2;
struct BIT
{
int tre[N];
#define lowbit(x) (x&(-x))
void insert(int x,int val){for(int i=x;i<=n;i+=lowbit(i))tre[i]+=val;}
int query(int x){int sum=0;for(int i=x;i;i-=lowbit(i))sum+=tre[i];return sum;}
int query(int l,int r){return query(r)-query(l-1);}
}T;
void dfs(int x)
{
ans+=T.query(dfn[x],dfn[x]+siz[x]-1); T.insert(dfn[x],1);
for(int i=e2.head[x];i;i=e2.nxt[i]) dfs(e2.ver[i]);
T.insert(dfn[x],-1);
}
int main()
{
freopen("charity.in","r",stdin); freopen("charity.out","w",stdout);
n=read(); read(); D1.init(); D2.init();
for(int i=2,x;i<=n;i++) x=read(),v[x].push_back(i),v[i].push_back(x);
for(int i=n;i>=1;i--) for(auto it:v[i]) if(it>i) e1.add(i,D1.find(it)),D1.merge(it,i);
for(int i=1;i<=n;i++) for(auto it:v[i]) if(it<i) e2.add(i,D2.find(it)),D2.merge(it,i);
e1.dfs(1); dfs(n); printf("%lld",ans);
return 0;
}

T4 欢乐豆

解题思路

正解是 线段树+最短路 ,但是貌似可以乱搞过。。

先把所有的关于 \(m\) 条边所涉及到的点记录下来,那么别的点到其他点的距离就是初始权值。

同时我们还需要再记录一下初始权值最小的点以保证我们再后面的最短路中对于附给大边权的情况可以跑回来。

然后对于每一个记录下来的点为源点跑最短路,一边跑一遍用并茶几维护,具体实现可以再向优先队列里面加入元素的时候记录一个 bool 值。

表示时候已经计算过了这个点到别的联通块的距离,就可以直接跑了。。。

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,INF=1e18;
int n,m,mn=INF,mnid,ans,cnt,dis[N],sta[N],id[N],s[N],fa[N];
bool vis[N];
struct Node
{
int pos,dat,can;
bool friend operator < (Node x,Node y){return x.dat>y.dat;}
};
vector< pair<int,int> > v[N];
bool comp(Node x,Node y){return x.dat<y.dat;}
priority_queue<Node> q;
int find(int x){if(fa[x]==x) return x; return fa[x]=find(fa[x]);}
void New(int x){if(id[x]) return ; sta[++cnt]=x; id[x]=cnt;}
void insert(int x,int val)
{
if(fa[x]!=x) return ; fa[x]=x+1; dis[x]=val;
q.push((Node){x,dis[x]+s[sta[x]],true});
for(auto it:v[x]) if(dis[it.first]>dis[x]+it.second)
q.push((Node){it.first,dis[it.first]=dis[x]+it.second});
}
void solve(int fro)
{
for(int i=1;i<=cnt+1;i++) dis[i]=INF,fa[i]=i;
dis[fro]=0; q.push((Node){fro,0,false});
while(!q.empty())
{
Node temp=q.top(); int x=temp.pos; q.pop();
if(!temp.can){insert(x,temp.dat);continue;}
for(auto it:v[x]) vis[it.first]=true;
for(int i=find(1);i<=cnt;i=find(i+1)) if(!vis[i]) insert(i,temp.dat);
for(auto it:v[x]) vis[it.first]=false;
}
}
#undef int
int main()
{
#define int long long
freopen("happybean.in","r",stdin); freopen("happybean.out","w",stdout);
n=read(); m=read(); for(int i=1;i<=n;i++) s[i]=read();
for(int i=1,x,y,val;i<=m;i++)
x=read(),y=read(),val=read(),New(x),New(y),
v[id[x]].push_back(make_pair(id[y],val));
for(int i=1;i<=n;i++) if(!id[i]&&s[i]<mn) mn=s[i],mnid=i; if(mn!=INF) New(mnid);
for(int i=1;i<=n;i++) if(!id[i]) ans+=(n-1)*s[i];
for(int i=1;i<=cnt;i++)
{
int minn=INF; solve(i);
for(int j=1;j<=cnt;j++) ans+=dis[j],minn=min(minn,dis[j]+s[sta[j]]);
ans+=(n-cnt)*minn;
}
printf("%lld",ans);
return 0;
}

NOIP模拟92&93(多校26&27)的更多相关文章

  1. NOIP模拟92(多校25)

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

  2. 2021.7.29考试总结[NOIP模拟27]

    T1 牛半仙的妹子图 做法挺多的,可以最小生成树或者最短路,复杂度O(cq),c是颜色数. 我考场上想到了原来做过的一道题影子,就用了并查集,把边权排序后一个个插入,记录权值的前缀和,复杂度mlogm ...

  3. Noip模拟63 2021.9.27(考场惊现无限之环)

    T1 电压机制 把题目转化为找那些边只被奇数环包含. 这样的话直接$dfs$生成一棵树,给每个点附上一个深度,根据其他的非树边都是返祖边 可以算出环内边的数量$dep[x]-dep[y]+1$,然后判 ...

  4. noip模拟26[肾炎黄·酱累黄·换莫黄]

    \(noip模拟26\;solutions\) 这个题我做的确实是得心应手,为啥呢,因为前两次考试太难了 T1非常的简单,只不过我忘记了一个定理, T2就是一个小小的线段树,虽然吧我曾经说过我再也不写 ...

  5. noip模拟27[妹子图·腿·腰](fengwu半仙的妹子们)

    \(noip模拟27\;solutions\) 这次吧,我本来以为我能切掉两个题,结果呢??只切掉了一个 不过,隔壁Varuxn也以为能切两个,可惜了,他一个都没切...... 确实他分比我高一点,但 ...

  6. NOIP模拟题17.9.26

    B 君的任务(task)[题目描述]与君初相识,犹如故人归.B 君看到了Z 君的第一题,觉得很难.于是自己出了一个简单题.你需要完成n 个任务,第i 任务有2 个属性ai; bi.其中ai 是完成这个 ...

  7. Noip模拟10 2021.6.27

    T1 入阵曲 好了,又一个考试败笔题. 也就是在那个时候,小 F 学会了矩阵乘法.让两个矩阵乘几次就能算出斐波那契数, 真是奇妙无比呢. 不过, 小 F 现在可不想手算矩阵乘法--他觉得好麻烦.取而代 ...

  8. 2021.7.28考试总结[NOIP模拟26]

    罕见的又改完了. T1 神炎皇 吸取昨天三个出规律的教训,开场打完T2 20pts直接大力打表1h. 但怎么说呢,我不懂欧拉函数.(其实exgcd都忘了 于是只看出最大平方因子,不得不线性筛,爆拿60 ...

  9. NOIP 模拟4 T2

    本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ...

随机推荐

  1. python 建站教程

    主端:安装nginx uwsgi django pymysql mysql安装mysql到http://repo.mysql.com/里面找 mysql57-community-release-el7 ...

  2. css 常用语法

    1.禁止某个元素内的任何选中操作: .classname{ -webkit-user-select: none; -moz-user-select: none; -ms-user-select: no ...

  3. logback日志入门超级详细讲解

    基本信息 日志:就是能够准确无误地把系统在运行状态中所发生的情况描述出来(连接超时.用户操作.异常抛出等等): 日志框架:就是集成能够将日志信息统一规范后输出的工具包. Logback优势 Logba ...

  4. amber模拟kcl水溶液

    最近刚开始学习amber软件,看网上的教程勉强知道怎么操作这个amber了.就暂时跑了个分子动力学,其他的啥也没处理.先把我的操作过程记录下来吧,免得日后忘记. 一.构建kcl.pdb结构 利用Gau ...

  5. Ubuntu18.04安装MySQL教程

    Ubuntu18.04下安装MySQL 提示:以下操作均在root权限下进行. # 查看有没有安装MySQL: dpkg -l | grep mysql # 安装MySQL: apt install ...

  6. 腾讯混合云存储 TStor 系列再添新成员,并行存储一体机正式发布

    最近国内某大型互联网公司依靠其数据优势成功上市,可见数据的重要性,而数据和存储密不可分,您真的知道自己需要更高性能存储吗? 在当今数据爆发式增长的时代,数据已经成为很多行业最重要的资源,没有之一. 数 ...

  7. React Native之新架构中的Turbo Module实现原理分析

    有段时间没更新博客了,之前计划由浅到深.从应用到原理,更新一些RN的相关博客.之前陆续的更新了6篇RN应用的相关博客(传送门),后边因时间问题没有继续更新.主要是平时空余时间都用来帮着带娃了,不过还是 ...

  8. 洛谷3244 落忆枫音 (拓扑图dp+式子)

    题目大意就是 给你一个DAG 然后添加一条边\(x->y\) ,询问以1为根的生成树的个数 QWQ 首先假设没有添加的边 答案就应该是 \[ans=\prod_{i=1}^{n} in[i] \ ...

  9. Tomcat实现自定义类加载器

    什么是类加载器? 这是官方给的定义 在 Java 虚拟机的实现中,初始类可以作为命令行参数提供. 或者,该实现可以提供一个初始类,该类设置一个类加载器,该类加载器依次加载应用程序. 初始类的其他选择也 ...

  10. 在hive中使用COALESCE进行空值处理

    COALESCE (expression_1, expression_2, ...,expression_n)依次参考各参数表达式,遇到非null值即停止并返回该值.如果所有的表达式都是空值,最终将返 ...