加载中…

返回上一页

CSP-S模拟12

下发文件和题解

由于题面在网上已经可以查询到,故放出题面,但仍请不要随意发布至网络上.

A. 开挂

题目描述

用一个,每次出现一个和前面相等的数就放入栈中,出现不相等的数就看它和上一个数之间有多少空位,每次贪心地选栈顶的与之配对.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define rg register
#define sinline static inline
#define rll rg ull
#define maxn 1000010
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ull read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
	return f?-x:x;
}
sinline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|'0');
}
ull n,ls,num=1,len,it,s;
ull ans;
ull a[maxn],b[maxn];
vector<ull> c,d;
int main()
{
	n=read();for(rll i=1;i<=n;i++) a[i]=read();for(rll i=1;i<=n;i++) b[i]=read();
	sort(a+1,a+n+1);sort(b+1,b+n+1);
	for(rll i=1;i<=n+1;i++)
	{
		if(a[i]!=a[i-1])
		{
			while((a[i]^ls)&&(!c.empty()))
				d.push_back(ls-c.back()),c.pop_back(),ls++;
			ls=a[i]+1;
		}
		else c.push_back(a[i]);
	}
	sort(d.begin(),d.end());s=d.size();
	for(rll i=1;i<=s;i++) ans+=d[s-i]*b[i];write(ans);
	return 0;
}

B. 叁仟柒佰万

题目描述

首先,如果每个子序列的 mex 值相同,那么每一个子序列上的 mex 值一定是整个序列的 mex 值.

那么显然这是一道 dp 题. 令 dp[i] 表示前 i 个点,它的 mex 相同的段有多少种可能. 然后用一个双指针扫一遍记录答案. 发现前面有一大部分可能没有贡献(即 mex 小于整个序列的),直接记录 sum 忽略它们从后面开始 dp.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 37000001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
	return f?-x:x;
}
sinline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|'0');
}
ll t,n,x,y,mx,tmx,k,s;
ll a[maxn],sum[maxn],dp[maxn];
bool fl[maxn],flag;
// sinline ll ksm(rll a,rll b) { rll ans=1; a%=mod; for(rll i=b;i;i>>=1) { if(i&1) ans=ans*a%mod; a=a*a%mod; } return ans; }
int main()
{
	t=read();while(t--)
	{
		memset(fl,0,sizeof(fl));memset(sum,0,sizeof(sum));memset(dp,0,sizeof(dp));flag=tmx=mx=0;
		if((n=read())==37000000) { x=read(); y=read(); a[1]=0; for(rll i=2;i<=n;i++) a[i]=(a[i-1]*x+y+i)&262143; }
		else for(rll i=1;i<=n;i++) a[i]=read();
		for(rll i=1;i<=n;i++) if(!a[i]) { flag=1;break; }
		// if(!flag) { write(ksm(2,n-1)); putn; continue; }
		for(rll i=1;i<=n;i++) { fl[a[i]]=1;if(mx==a[i]) while(fl[mx]) mx++; }
		memset(fl,0,sizeof(fl));
		for(k=1;k<=n;k++) { sum[a[k]]++; fl[a[k]]=1; if(tmx==a[k]) while(fl[tmx]) tmx++; if(tmx==mx) break; }
		s=dp[0]=dp[k]=1;
		for(rll i=k+1,r=1;i<=n;i++)
		{
			sum[a[i]]++;
			while(r<i&&(a[r]>mx||sum[a[r]]>1))
			{
				if(r>=k) s=(s+dp[r])%mod;sum[a[r]]--;r++;
			}
			dp[i]=s;// cout<<dp[i]<<' ';
		}
		/*putn;*/write(dp[n]);putn;
	}
	return 0;
}

C. 超级加倍

题目描述

类似于一个 kruskal 重构树的做法.
笛卡尔树的做法拓展到树上.

对于求这种路径显然是一个范围问题. 从小到大加入每个节点,对于每新加入的节点 v,合并已加入节点 uv,把 u 连通块的设置为 v,自然并查集就行了.

重构树上的两个点的 lca 就是真实路径上的最小值.

所以可以反过来重新建一棵树,这样两个点的 lca 就是真实路径上的最大值了.

所以在第一棵树上求 dfs 序。在第二棵树上遍历,用一个 bit 统计答案即可.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 2000001
#define elif else if
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
	return f?-x:x;
}
sinline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|'0');
}

template<typename T,size_t sz>
class bit
{
#define lowbit(x) (x&-x)
private:
	T c[sz];
public:
	inline void update(rg T x,rg T n,rg T v) { for(rg T i=x;i<=n;i+=lowbit(i)) c[i]+=v; }
	inline T query(rg T x) { /*write(x);putn;*/ rg T ans=0; for(rg T i=x;i;i-=lowbit(i)) ans+=c[i];  /*write(ans);putn;*/ return ans; }
#undef lowbit
};

ll n,f[maxn],dfn[maxn],sz[maxn],cnt,ans;
vector<ll> g[maxn],g1[maxn]/*重构树*/;
bit<ll,maxn> t;
sinline ll find(rll x) { if(x!=f[x]) f[x]=find(f[x]); return f[x]; }
sinline void dfs(rll x)
{
	dfn[x]=++cnt;sz[x]=1;// cout<<x<<' '<<dfn[x]<<endl;
	for(rll i=0;i<g1[x].size();i++) { rll to=g1[x][i]; dfs(to); sz[x]+=sz[to]; }
}
sinline void dfs1(rll x)
{
	// cout<<x<<' '<<dfn[x]<<endl;
	ans+=t.query(dfn[x]+sz[x]-1)-t.query(dfn[x]-1);
	t.update(dfn[x],n,1);// write(t.query(dfn[x]));
	for(rll i=0;i<g1[x].size();i++) { rll to=g1[x][i]; dfs1(to); }
	t.update(dfn[x],n,-1);
}
int main()
{
	n=read();for(rll i=1,t;i<=n;i++) t=read(),g[t].push_back(i),g[i].push_back(t);
	for(rll i=1;i<=n;i++) f[i]=i;
	for(rll i=n-1;i;i--)
		for(rll j=0;j<g[i].size();j++)
		{
			rll to=g[i][j];if(to>i) g1[i].push_back(find(to)),f[find(to)]=i;
		}
	dfs(1);for(rll i=1;i<=n;i++) f[i]=i;for(rll i=1;i<=n;i++) g1[i].clear();
	for(rll i=2;i<=n;i++)
		for(rll j=0;j<g[i].size();j++)
		{
			rll to=g[i][j];if(to<i) g1[i].push_back(find(to)),f[find(to)]=i;
		}
	dfs1(n);write(ans);
	return 0;
}

D. 欢乐豆

题目描述

贺的(原网址).

点击查看代码
#include<bits/extc++.h>
#define ll long long
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 200001
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
	return f?-x:x;
}
sinline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|'0');
}
struct node
{
	ll v,id;
	inline friend bool operator<(rg node a,rg node b) { return a.v<b.v; }
}b[maxn];
struct tree
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
	ll mnv,pos,tag;
}t[maxn<<2];
ll n,m,x,y,z,k,tot,ans;
ll a[maxn],f[maxn];
ll id[maxn],num[maxn],dis[maxn];
vector<ll> g[maxn];
vector<pll> h,g1[maxn];
struct nd
{
	ll a,b;
	inline friend bool operator<(rg nd a,rg nd b) { return id[a.a]<id[b.a]; }
};
vector<nd> q;
multiset<ll> s;
__gnu_pbds::list_update<pll,ll> mp;
sinline ll find(rll x) { if(x^f[x]) f[x]=find(f[x]); return f[x]; }
sinline void pushup(rll rt)
{
	if(t[ls(rt)].mnv==t[rs(rt)].mnv&&t[ls(rt)].mnv==-1) { t[rt].mnv=-1; return; }
	if((!~t[ls(rt)].mnv)||(t[ls(rt)].mnv>t[rs(rt)].mnv&&(~t[rs(rt)].mnv))) t[rt].mnv=t[rs(rt)].mnv,t[rt].pos=t[rs(rt)].pos;
	else t[rt].mnv=t[ls(rt)].mnv,t[rt].pos=t[ls(rt)].pos;
}
sinline void pushdown(rll rt)
{
	if(t[rt].tag!=(INT_MAX))
	{
		t[ls(rt)].mnv=min(t[rt].tag,t[ls(rt)].mnv);t[ls(rt)].tag=min(t[rt].tag,t[ls(rt)].tag);
		t[rs(rt)].mnv=min(t[rt].tag,t[rs(rt)].mnv);t[rs(rt)].tag=min(t[rt].tag,t[rs(rt)].tag);
		t[rt].tag=(INT_MAX);
	}
}
sinline void build(rll rt,rll l,rll r)
{
	t[rt].mnv=t[rt].tag=(INT_MAX);
	if(l==r) { t[rt].pos=num[l]; return; }
	rll mid=(l+r)>>1;
	build(ls(rt),l,mid); build(rs(rt),mid+1,r);
	pushup(rt);
}
sinline void upd(rll rt,rll l,rll r,rll x,rll y,rll v)
{
	if(x<=l&&r<=y) { t[rt].mnv=min(t[rt].mnv,v); t[rt].tag=min(t[rt].tag,v); return; }
	pushdown(rt);rll mid=(l+r)>>1;
	if(x<=mid) upd(ls(rt),l,mid,x,y,v);if(y>mid) upd(rs(rt),mid+1,r,x,y,v);
	pushup(rt);
}
sinline ll query(rll rt,rll l,rll r,rll pos)
{
	if(l==r) return t[rt].mnv;
	if(t[rt].tag!=(INT_MAX)) pushdown(rt);
	rll mid=(l+r)>>1;
	if(pos<=mid) return query(ls(rt),l,mid,pos);
	else return query(rs(rt),mid+1,r,pos);
}
sinline void spfa(rll x)
{
	upd(1,1,tot,id[x],id[x],0);
	while(~t[1].mnv)
	{
		rll p=t[1].pos,d=t[1].mnv,ls=0; dis[p]=d;
		q.clear();
		for(rll i=0;i<g1[p].size();i++) q.push_back((nd) { g1[p][i].first,g1[p][i].second });
		sort(q.begin(),q.end());
		for(rll i=0;i<q.size();i++)
		{
			rll ta=q[i].a,mnd=d+min(q[i].b,a[p]+k);
			if(ls+1<=id[ta]-1) upd(1,1,tot,ls+1,id[ta]-1,d+a[p]);ls=id[ta];
			if(query(1,1,tot,id[ta])>mnd) upd(1,1,tot,id[ta],id[ta],mnd);
		}
		if(ls+1<=tot) upd(1,1,tot,ls+1,tot,d+a[p]);
		upd(1,1,tot,id[p],id[p],-1);
	}
}
sinline void get(rll x)
{
	for(rll i=0;i<g[x].size();i++) s.erase(s.find(a[g[x][i]]));
	if(!s.empty()) k=*s.begin(); else k=(INT_MAX);
	tot=0;
	for(rll j=0;j<g[x].size();j++) id[g[x][j]]=++tot,num[tot]=g[x][j];
	for(rll i=0;i<g[x].size();i++)
	{
		build(1,1,tot);spfa(g[x][i]);
		for(rll j=0;j<g[x].size();j++) ans+=dis[g[x][j]];
		rll k=a[g[x][i]];
		for(rll j=0;j<g[x].size();j++) k=min(k,dis[g[x][j]]+a[g[x][j]]);
		ans+=(n-g[x].size())*k;
	}
	for(rll i=0;i<g[x].size();i++) s.insert(a[g[x][i]]);
}
int main()
{
	n=read();m=read();for(rll i=1;i<=n;i++) a[i]=read(),s.insert(a[i]),f[i]=i;
	for(rll i=1,ls;i<=m;i++)
	{
		x=read();y=read();z=read();
		if(find(x)!=find(y)) f[find(x)]=find(y);
		if(!mp[(pll) { x,y }]) h.push_back((pll) { x,y });
		mp[(pll) { x,y }]=z;
	}
	for(rll i=0;i<h.size();i++)
		g1[h[i].first].push_back((pll) { h[i].second,mp[(pll) { h[i].first,h[i].second }] });
	for(rll i=1;i<=n;i++) g[find(i)].push_back(i);
	for(rll i=1;i<=n;i++)
	{
		if(g[find(i)].size()==1) ans+=(n-1)*a[i];
		else if(find(i)==i) get(find(i));
	}
	write(ans);
	return 0;
}
posted @ 2022-09-26 16:47  1Liu  阅读(10)  评论(0)    收藏  举报