多校冲刺 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);
}
posted on 2021-11-10 19:32  JYFHYX  阅读(58)  评论(0编辑  收藏  举报