【比赛】高一小学期2

挺唐的比赛,一道数位 dp 原题一道平衡树,然后 T1 数据范围还整错了。。

没图了呜呜

【比赛】高一小学期2

$Rank$
赛时

image

日前赛后

image
image


T1 同类分布

思路

印象里为数不多搞懂了的数位 dp,但过太久忘了,只能赛时打暴力

后来发现跟正解很接近了,只是在 dfs 前的预处理上出了点问题。

用记搜做,记搜前循环遍历所有可能的数字和 \(s\) 作为模数,\(len\) 为当前搜到的位数,\(sum\) 为当前所有数字和,\(logos\) 存当前数对 \(s\) 取模的结果,\(lmt\) 判断当前是否达到上限。

由于每次模数 \(s\) 不同,所以 dp 数组需要每轮清空,多次用到 memset,所以数组大小要开适量。

Code:

#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
ll a,b,cnt,s;
ll num[20],f[20][163][163];
// 最多19位数,sum 最大值为 1+18*9=162
namespace Wisadel
{
	inline ll Wdfs(int len,int sum,int logos,int lmt)
	{
		if(sum+9*len<s) return 0;// 小剪枝 
		if(!lmt&&f[len][sum][logos]!=-1) return f[len][sum][logos];// 记录过 
		if(!len) return logos==0&&sum==s;// 搜到末尾 
		ll res=0,maxx=lmt?num[len]:9;
		fo(i,0,maxx)
			res+=Wdfs(len-1,(sum+i),(logos*10+i)%s,lmt&&i==maxx);
		if(!lmt) f[len][sum][logos]=res;// 记忆 
		return res;
	}
	inline ll Ws(ll x)
	{
		cnt=0;ll ans=0;
		while(x) num[++cnt]=x%10,x/=10;
		for(s=1;s<=cnt*9;s++)
		{
			memset(f,-1,sizeof f);
			ans+=Wdfs(cnt,0,0,1);
		}
		return ans;
	}
	short main()
	{
		freopen("a.in","r",stdin),freopen("a.out","w",stdout);
		a=qr,b=qr;
		printf("%lld\n",Ws(b)-Ws(a-1));
		return Ratio;
	}
}
int main(){return Wisadel::main();}

T2 千山鸟飞绝

思路

首先(才不是只会)考虑暴力的思路,开一个结构体存每只鸟的有关信息,用 map 将坐标离散成点,\(num_i\) 存每个点实时鸟数量,\(pre_{i,j}\) 表示 \(i\) 点第 \(j\) 只鸟的下标。

注意到有鸟会飞走,静态数组不能很好地进行删除替换,所以我们令飞走的第 \(j\) 只鸟下标为 \(-1\),然后还要一个 \(ttot_i\) 记录 \(i\) 点一共来过多少只鸟。

写一个 pushup 操作,每当鸟变化后 \(num_i>1\) 时运行,更新该点每个鸟的信息。

暴力本来期望的分 \(50pts\),但我只拿了 \(40pts\),怎么绘世呢?

考虑鸟的数量最多为 \(30000\),为了防止 MLE,我只把 \(pre\) 数组开到了 \(30000\times 150\),然而那个测试点中显然有个点来了超过 \(150\) 只鸟,然后就 GG 了。

暴力 $50pts's\,code$:
#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=30005;
int n,t,tot;
struct rmm
{
	int id,xx,yy,ww,zb;
	int sq=0,tj=0;
}bd[N];
map<pair<int,int>,int>mp;
int num[N*2],pre[N*2][308],ttot[N*4];
namespace Wisadel
{
	void Wpushup(int zbb)
	{
		fo(i,1,ttot[zbb])
		{
			if(pre[zbb][i]==-1) continue;
			int maxsq=-2147483647,k=pre[zbb][i];
			bd[k].tj=max(bd[k].tj,num[zbb]-1);
			fo(j,1,ttot[zbb])
			{
				if(i==j) continue;
				int kk=pre[zbb][j];
				maxsq=max(maxsq,bd[kk].ww);
			}
			bd[k].sq=max(bd[k].sq,maxsq);
		}
	}
	void Wfin(int v)
	{
		fo(i,1,ttot[bd[v].zb])
			if(pre[bd[v].zb][i]==v)
			{
				pre[bd[v].zb][i]=-1;
				break;
			}
		num[bd[v].zb]--;
	}
	short main()
	{
		freopen("a.in","r",stdin),freopen("a.out","w",stdout);
		n=qr;
		fo(i,1,n)
		{
			bd[i].id=i,bd[i].ww=qr,bd[i].xx=qr,bd[i].yy=qr;
			if(!mp[{bd[i].xx,bd[i].yy}]) mp[{bd[i].xx,bd[i].yy}]=++tot;
			bd[i].zb=mp[{bd[i].xx,bd[i].yy}];
			num[bd[i].zb]++,ttot[bd[i].zb]++,pre[bd[i].zb][ttot[bd[i].zb]]=i;
			if(num[bd[i].zb]>1) Wpushup(bd[i].zb);
		}
		t=qr;
		while(t--)
		{
			int a=qr,b=qr,c=qr;int i=a;
			Wfin(a);
			if(!mp[{b,c}]) mp[{b,c}]=++tot;
			bd[i].xx=b,bd[i].yy=c;
			bd[i].zb=mp[{b,c}];
			num[bd[i].zb]++,ttot[bd[i].zb]++,pre[bd[i].zb][ttot[bd[i].zb]]=i;
			if(num[bd[i].zb]>1) Wpushup(bd[i].zb);
		}
		fo(i,1,n) printf("%lld\n",1ll*bd[i].sq*bd[i].tj);
		return Ratio;
	}
}
int main(){return Wisadel::main();}

然后考虑平衡树做法。打出暴力能加深对题目的理解(确信),现在我们知道可以用 Splay 维护每个点的有关信息,每秒进行以下操作:

  • 将该鸟从原树中删除;
  • 将该鸟的武力值更新到前往的树中,用标记记录树上士气值和团结值;
  • 将该树中的士气值更新给该鸟;
  • 将该鸟插入前往的树对应的 Splay 中。

之后下放标记,输出答案即可。

Code:

#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=30005;
int n,t,tot;
pair<int,int>zb[N];
int rt[N<<2],fa[N],son[N][2],siz[N];// Splay 
int maxv[N],v[N],sq[N],tj[N];// 每个鸟的信息 
int sqbj[N],tjbj[N];// 标记 
map<pair<int,int>,int>mp;// 离散化 
namespace Wisadel
{
	#define ls(x) son[x][0]
	#define rs(x) son[x][1]
	void Wcler(int x)
	{//飞走 清除数据 
		fa[x]=ls(x)=rs(x)=0;siz[x]=1;maxv[x]=v[x];sqbj[x]=tjbj[x]=0; 
	}
	void Wpushup(int x)
	{
		siz[x]=siz[ls(x)]+siz[rs(x)]+1;
		maxv[x]=max(v[x],max(maxv[ls(x)],maxv[rs(x)]));
	}
	//传递标记 
	void Wmark(int x,int a,int b)
	{
		sqbj[x]=max(sqbj[x],a),sq[x]=max(sq[x],sqbj[x]);
		tjbj[x]=max(tjbj[x],b),tj[x]=max(tj[x],tjbj[x]);
	}
	void Wpushdown(int x)
	{
		if(sqbj[x]) Wmark(ls(x),sqbj[x],0),Wmark(rs(x),sqbj[x],0),sqbj[x]=0;
		if(tjbj[x]) Wmark(ls(x),0,tjbj[x]),Wmark(rs(x),0,tjbj[x]),tjbj[x]=0;
	}
	void Wrotate(int x)
	{
		int y=fa[x],z=fa[y],fla=rs(y)==x;
		fa[x]=z;if(z) son[z][rs(z)==y]=x;
		son[y][fla]=son[x][!fla],fa[son[y][fla]]=y;
		son[x][!fla]=y,fa[son[x][!fla]]=x;
		Wpushup(y),Wpushup(x);
	}
	void Wpdrt(int x)
	{// 从该 Splay 的根开始下放 
		if(fa[x]) Wpdrt(fa[x]);
		Wpushdown(x);
	}
	void Wsplay(int x)
	{
		Wpdrt(x);
		for(int y=fa[x];y;Wrotate(x),y=fa[x])
			if(fa[y])
				((rs(y)==x)^(rs(fa[y])==y))?Wrotate(x):Wrotate(y);
		rt[mp[zb[x]]]=x;
	}
	void Wins(pair<int,int> c,int x)
	{// 飞来 
		zb[x]=c;
		if(!mp[c])
		{
			mp[c]=++tot,rt[mp[c]]=x;
			return;
		}
		int y=rt[mp[c]];
		sq[x]=max(sq[x],maxv[y]);
		tj[x]=max(tj[x],siz[y]);
		Wmark(y,v[x],siz[y]);
		ls(x)=y,fa[ls(x)]=x;
		rt[mp[c]]=x;
		Wpushup(x);
	}
	void Wdel(int x)
	{// 飞走 处理原树 
		pair<int,int> c=zb[x];
		Wsplay(x);
		if(!ls(x))
		{
			rt[mp[c]]=rs(x),fa[rt[mp[c]]]=0;
			return;
		}
		int y=ls(x);
		while(rs(y)) y=rs(y);
		Wsplay(y);
		rs(y)=rs(x),fa[rs(y)]=y;
		Wpushup(y);
	}
	void Wpdall(int x)
	{// 下放所有标记 
		if(!x) return;
		Wpushdown(x);
		Wpdall(ls(x)),Wpdall(rs(x));
	}
	short main()
	{
		freopen("a.in","r",stdin),freopen("a.out","w",stdout);
		n=qr;
		fo(i,1,n)
		{
			siz[i]=1;maxv[i]=v[i]=qr;
			int a=qr,b=qr;
			Wins({a,b},i);
		}
		t=qr;
		while(t--)
		{
			int a=qr,b=qr,c=qr;
			Wdel(a),Wcler(a);
			Wins({b,c},a);
		}
		fo(i,1,tot) Wpdall(rt[i]);
		fo(i,1,n) printf("%lld\n",1ll*sq[i]*tj[i]);
		return Ratio;
	}
}
int main(){return Wisadel::main();}

完结撒花~

posted @ 2024-07-08 11:34  DrRatio  阅读(32)  评论(0编辑  收藏  举报