多校冲刺 NOIP 20211110 模拟 (27)
emmm...开考后发现T1随便贪心一下就好了,40分钟直接切了,然后开T2,想了个\(O(n^2)\)暴力,结果没有想到优化然后就跳了
T3的话淀粉质大概有6,70分,准备写完T4之后再看一下,然后就去看T4,T4有20分是白给的
然后5分钟拿到,然后其他部分也没啥思路,然后又回去看T3,时间大概是10点20,觉得自己1个小时应该可以解决,
思路大话大概就是树上的二维偏序问题,自己一心扎在了子树合并上emmm。。但其实容斥打法更好实现
然后调了半天发现合并错了,再改也来不及了,以后淀粉质还是打容斥做法吧。。。
眼睁睁得看着手中得70分飞走,心里挺不是滋味的
最后100+50+10+20,发现T2是个sb题,考完一下就想到了,早知道就不该把所有的时间放T3上了,以后还是要合理安排时间
T1 开挂
首先\(b_{i}\)的顺序是可以随便打乱的,那么可以先求出所有\(a_{i}\)的\(dealt\)将其排序择优录取
至于\(a_{i}\)的话,发现小元素要根据较大的元素是否出现来变化,所以可以先变化较大的元素,而且无论变化顺序如何,最优的结果是一定的
所以根据不等式的性质,可以证明先变化较大的是不劣的
那么可以开两个set,一个维护当前的元素,另一个维护当前所有元素未出现过的\(a_{i}+1\)
判断这个元素是否在第一个set里出现过,如果出现过,那么就\(lower\ bound\)一个最小的未出现的位置然后删掉就可以了
然后直接统计答案就行
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int Mxdt=1e5;
inline char gc()
{
static char buf[Mxdt],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int t=0,f=0;char v=gc();
while(v<'0')f|=(v=='-'),v=gc();
while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
return f?-t:t;
}
const int maxn=1e6+5;
int a[maxn],b[maxn],n;
bool cmp(int a,int b){return a>b;}
set<int>st,ts;ull ans;
int tmp[maxn],top;
signed main()
{
freopen("openhook.in","r",stdin);
freopen("openhook.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) b[i]=read();
sort(b+1,b+1+n);sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
if(st.find(a[i])==st.end())
{
st.insert(a[i]);
if(ts.find(a[i])!=ts.end()) ts.erase(ts.find(a[i]));
if(st.find(a[i]+1)==st.end()) ts.insert(a[i]+1);
}
else
{
int it=*ts.lower_bound(a[i]);
tmp[++top]=it-a[i];
st.insert(it);ts.erase(ts.find(it));
if(st.find(it+1)==st.end()) ts.insert(it+1);
}
}
sort(tmp+1,tmp+1+top,cmp);
for(int i=1;i<=top;i++) ans=ans+1ull*tmp[i]*b[i];
cout<<ans<<endl;
}
T2 叁仟柒佰万
一个sb题目,可是考场上大部分时间都给T3了,很是生气
首先可以有一个比较简单的dp
设\(dp_{i}\)为前\(i\)个数分组的方案数,转移的话就是\(dp_{i}=dp_{k}[bo_{k+1,i}==1]\)
其中\(bo_{i,j}\)表示i到j出现了所有小于等于全局\(mex\)的数
然后发现可以随便前缀和优化一下,然后就\(O(n)\)了
#include<bits/stdc++.h>
using namespace std;
const int Mxdt=1e6;
inline char gc()
{
static char buf[Mxdt],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int t=0,f=0;char v=gc();
while(v<'0')f|=(v=='-'),v=gc();
while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
return f?-t:t;
}
const int mod=1e9+7;
const int maxn=37000010;
int tong[maxn],f[maxn],a[maxn],n,x,y;
inline int ksm(int x,int y)
{
int res=1;x=x%mod;
for(;y;y>>=1){if(y&1)res=1ll*res*x%mod;x=1ll*x*x%mod;}
return res;
}
signed main()
{
freopen("clods.in","r",stdin);
freopen("clods.out","w",stdout);
int t=read();
while(t--)
{
n=read();
if(n<37000000) for(int i=1;i<=n;i++)a[i]=read(),tong[i]=0;
else
{
x=read();y=read();a[1]=0;tong[a[1]]++;
for(int i=2;i<=n;i++)
a[i]=(1ll*a[i-1]*x+y+i)&262143,tong[a[i]]++;
}
int gen=0;
if(n==37000000){for(int i=0;i<=n;i++){if(!tong[i]){gen=i;break;}tong[i]=0;}}
else{
tong[0]=0; for(int i=1;i<=n;i++)tong[a[i]]++;
for(int i=0;i<=n;i++)if(!tong[i]){gen=i;break;}
}
int tmp=0,ks=0;for(int i=0;i<=n;i++)tong[i]=0,f[i]=0;
for(int i=1;i<=n;i++)
{
++tong[a[i]];
while(tong[tmp]) tmp++;
if(tmp==gen){ks=i;break;}
}
int l=1;f[ks]=1;
for(int i=ks+1;i<=n;i++)
{
++tong[a[i]];f[i]=1;
while(((tong[a[l]]>1&&a[l]<gen)||a[l]>gen)&&l<i)
{tong[a[l]]--;l++;}f[i]=(f[i]+f[l-1]+f[i-1])%mod;
}
printf("%d\n",(f[n]-f[n-1]+mod)%mod);
}
}
T3
可以建立一棵类似于kruskal重构树的东西,在\(T_{1}\)中,\(x,y\)的\(LCA\)为\(x,y\)之间最小的
\(T_{2}\)中为最大的,然后\(dfs+BIT\)就完美解决了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int Mxdt=100000;
inline char gc(){
static char buf[Mxdt],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
int t=0,f=0;char v=gc();
while(v<'0')f|=(v=='-'),v=gc();
while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
return f?-t:t;
}
const int maxn=2e6+5;
int f[maxn];
inline int getfa(int x){return f[x]==x?x:f[x]=getfa(f[x]);}
int minn[maxn],maxx[maxn],siz[maxn],n,dfn[maxn];
vector<int>p[maxn];
int head[maxn],num;
struct edge{int to,nxt;}e[maxn<<1];
inline void add(int x,int y)
{e[++num]=(edge){y,head[x]};head[x]=num;}
struct szsz{
#define lowbit(x) (x&(-x))
int c[maxn];
inline void update(int x,int val)
{for(;x<=n;x+=lowbit(x))c[x]+=val;}
inline int query(int x)
{int res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
}T;
inline void merge1(int x,int y)
{
int fx=getfa(x),fy=getfa(y);
if(fx==fy) return ;
if(fx<fy) f[fy]=fx,add(fx,fy);
else f[fx]=fy,add(fy,fx);
}
inline void merge2(int x,int y)
{
int fx=getfa(x),fy=getfa(y);
if(fx==fy) return ;
if(fx>fy) f[fy]=fx,add(fx,fy);
else f[fx]=fy,add(fy,fx);
}
int cnt=0;ll ans=0;
inline void dfs1(int x)
{
dfn[x]=++cnt;siz[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{int y=e[i].to;dfs1(y);siz[x]+=siz[y];}
}
inline void dfs2(int x)
{
ans+=T.query(siz[x]+dfn[x]-1)-T.query(dfn[x]-1);
T.update(dfn[x],1);
for(int i=head[x];i;i=e[i].nxt){int y=e[i].to;dfs2(y);}
T.update(dfn[x],-1);
}
signed main()
{
freopen("charity.in","r",stdin);
freopen("charity.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)
{
f[i]=i;
int x=read();
if(i!=1)
{
p[x].push_back(i);
p[i].push_back(x);
}
}
for(int i=n;i>=1;i--) for(auto y:p[i]) if(y>i) merge1(y,i);
dfs1(1);
for(int i=1;i<=n;i++)f[i]=i;num=0;memset(head,0,sizeof(head));
for(int i=1;i<=n;i++) for(auto y:p[i]) if(y<i) merge2(y,i);
dfs2(n);
printf("%lld\n",ans);
}
T4 欢乐豆
最多会有m个点发生距离改变,那么对这m个点跑dij,每条边只被松弛一次,所以复杂度是\(O(m^2log(m))\)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){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 maxn=1e5+5;
const ll inf=1e18+7;
struct edge{int to,w;};
struct node{
int id,op;ll d;
bool operator<(node x)const{return d>x.d;}
};
ll ans,dis[maxn],mn;int c[maxn],pos[maxn],fa[maxn],n,m,sq[maxn],fl[maxn],C,fz;
inline int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
vector<edge>vec[maxn];priority_queue<node>q;
inline void dij(int x)
{
for(int i=1;i<=C;i++) fa[i]=i,dis[i]=inf;
fa[C+1]=C+1;q.push((node){x,0,dis[x]=0});
while(!q.empty())
{
node e=q.top();q.pop();
int ps=e.id;
if(e.op)
{
for(auto y:vec[ps]) fl[y.to]=1;
for(int i=getfa(1);i<=C;i=getfa(i+1))
if(!fl[i])
{
int x=i,w=e.d;
if(fa[x]!=x) continue;
dis[x]=w;fa[x]=fa[x]+1; q.push((node){x,1,w+c[sq[x]]});
for(auto v:vec[x]) if(dis[v.to]>dis[x]+v.w)
q.push({v.to,0,dis[v.to]=dis[x]+v.w});
}
for(auto k:vec[ps])fl[k.to]=0;
}
else
{
int x=ps,w=e.d;
if(fa[x]==x)
{
dis[x]=w;fa[x]=fa[x]+1; q.push((node){x,1,w+c[sq[x]]});
for(auto v:vec[x]) if(dis[v.to]>dis[x]+v.w)
q.push({v.to,0,dis[v.to]=dis[x]+v.w});
}
}
}
}
signed main()
{
freopen("happybean.in","r",stdin);
freopen("happybean.out","w",stdout);
n=read();m=read();c[0]=1e9;
for(int i=1;i<=n;i++)c[i]=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read();
if(!pos[x]) sq[pos[x]=++C]=x;
if(!pos[y]) sq[pos[y]=++C]=y;
vec[pos[x]].push_back((edge){pos[y],z});
}
for(int i=1;i<=n;i++) if(!pos[i]&&c[fz]>c[i])fz=i;
if(fz&&!pos[fz]) sq[pos[fz]=++C]=fz;
for(int i=1;i<=n;i++) if(!pos[i])ans+=1ll*c[i]*(n-1);
for(int i=1;i<=C;i++)
{
dij(i);mn=inf; for(int j=1;j<=C;j++)
ans+=dis[j],mn=min(mn,dis[j]+c[sq[j]]);
ans+=mn*(n-C);
}
printf("%lld\n",ans);
}