挺唐的比赛,一道数位 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=100005;
int n,t,tot;
pair<int,int>zb[N];
int rt[N<<2],fa[N],son[N][2],siz[N];
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){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();}
完结撒花~