前言

由于太菜了,多校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. promise对象总结

    一.Promise是异步编程的一种解决方案,它是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可以获取异步操作的消息.Promis ...

  2. 51nod1355-斐波那契的最小公倍数【min-max容斥】

    正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1355 题目大意 定义\(f_i\)表示斐波那契的第\(i\)项,给出一个 ...

  3. Python Pandas的使用 !!!!!详解

     Pandas是一个基于python中Numpy模块的一个模块 Python在数据处理和准备⽅⾯⼀直做得很好,但在数据分析和建模⽅⾯就差⼀些.pandas帮助填补了这⼀空⽩,使您能够在Python中执 ...

  4. FastAPI 学习之路(七)字符串的校验

    系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...

  5. 2020.10.10--pta阶梯赛练习2补题

    7-3.N个数求和 本题的要求很简单,就是求N个数字的和.麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式. 输入格式: 输入第一行给出一个正整数N(≤100).随后 ...

  6. Ubuntu安装 配置GCC和Vim

    VMware14.0和Ubuntu镜像安装 https://mp.weixin.qq.com/s/045wrbdv92PkUQn2abddvA 适应屏幕设置 按照下列流程检查虚拟机设置 查看 -> ...

  7. 【Java虚拟机3】类加载器

    前言 Java虚拟机设计团队有意把类加载阶段中的"通过一个类的全限定名来获取描述该类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类. ...

  8. 【UE4 C++】 Datatable 读写、导入导出 CSV/Json

    Datatable 读取行数据 1. 创建结构体 继承自 FTableRowBase USTRUCT(BlueprintType) struct FSimpleStruct :public FTabl ...

  9. Java:LinkedList类小记

    Java:LinkedList类小记 对 Java 中的 LinkedList类,做一个微不足道的小小小小记 概述 java.util.LinkedList 集合数据存储的结构是循环双向链表结构.方便 ...

  10. AIApe问答机器人项目Scrum Meeting博客汇总

    荡起双桨 Scrum Meeting 博客汇总 一.Alpha阶段 AIApe问答机器人Scrum Meeting 4.23 AIApe问答机器人Scrum Meeting 4.25 AIApe问答机 ...