挺唐的比赛,一道数位 dp 原题一道平衡树,然后 T1 数据范围还整错了。。 没图了呜呜
【比赛】高一小学期2
$Rank$
赛时
日前赛后
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();}
完结撒花~
标签:bd,qr,比赛,rs,int,一小,zb,学期,ch From: https://www.cnblogs.com/Ratio-Yinyue1007/p/18289505