前言

由于太菜了,多校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. VUE页面跳转方式

    一.to +跳转路径 <router-link to="/">跳转到主页</router-link> <router-link :to="{ ...

  2. 『Python』matplotlib划分画布的主要函数

    1. subplot() 绘制网格区域中几何形状相同的子区布局 函数签名有两种: subplot(numRows, numCols, plotNum) subplot(CRN) 都是整数,意思是将画布 ...

  3. CF1137F-Matches Are Not a Child‘s Play【LCT】

    正题 题目链接:https://www.luogu.com.cn/problem/CF1137F 题目大意 给出\(n\)个点的一棵树,第\(i\)个点权值为\(i\). 一棵树的删除序列定义为每次删 ...

  4. Markdown 相关语法

    MD语法博客:https://www.cnblogs.com/Jetictors/p/8506757.html 公式 \[\mathbf{x}_{t}=\Phi_{t}\left(\mathbf{x} ...

  5. 如何使用云效Flow做质量检测,保障高质量的交付速度

    使用云效Flow做质量检测,保障高质量的交付速度,云效「Flow」 提供代码扫描. 安全扫描和各种自动化测试能力,支持人工测试卡点.自动化验证卡点等多种质量红线,确保业务质量.云效流水线 Flow 流 ...

  6. HCNP Routing&Switching之路由引入导致的问题及解决方案

    前文我们了解了路由引入相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15359902.html:今天我们来讨论下由于路由引入所导致的问题以及怎么避免此 ...

  7. C++核心编程 1 程序的内存模型

    1.内存分区模型 C++程序在执行时,将内存大方向划分为4个区域 代码区:存放函数体的二进制代码,由操作系统进行管理(写的所有代码都在代码区) 全局区:存放全局变量.静态变量以及常量 栈   区:由编 ...

  8. $\Large{\LaTeX}$ 常用公式

    $$\Large{\LaTeX}$$: \[\Large{\LaTeX} \] $ $ 表示行内 $$ $$ 表示独立 $\operatorname{lcm}(x)$\(\operatorname{l ...

  9. 题解 P6454 麻将 加强版

    题目传送门 题目大意 不想写了,直接看题面吧. 思路 被这个题搞自闭了,因为读错题目想一个非常恶心的东西想了一场考试,然后就删代码,然后就被骂了.哎. 需要注意的是:我们只能选一次雀头 于是,不难看出 ...

  10. 初探JavaScript PDF blob转换为Word docx方法

    PDF转WORD为什么是历史难题 PDF 转Word 是一个非常非常普遍的需求,可谓人人忌危,为什么如此普遍的需求,却如此难行呢,还得看为什么会有这样的一个需求: PDF文档遵循iOS32000的规范 ...