比赛传送门
作者: fn
签到题
H题 Happy Number / 快乐数
题目大意
求第n个只包含2,3,6的正整数。
考察内容
分析
• 首先需要确定出 k 大数有多少位
• 显然1位的、2位的…分别有3,
3
2
3^2
32 ,⋯ 个
• 于是我们知道了 k 大数是 x 位下第 k’大的
• 然后我们可以把 2 看做 0,3 看做 1 ,6 看做 2
• 问题就转换成了三进制数转换
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int num[4]={6,2,3,0};
ll n,m,t=1;
int x[40];
int main(){
ios::sync_with_stdio(0); cin.tie(0);
cin>>n;
for(int i=3;n-i>0;i*=3){
n-=i;
t++;
}
for(int i=t;i>=1;i--){
x[i]=num[n%3];
n=(n+2)/3; // 向上取整
}
for(int i=1;i<=t;i++) cout<<x[i];
}
进阶题
I题 Incentive Model / 激励模型
题目大意
矿工A、B在挖矿,给定
a
a
a ,挖矿概率
p
A
=
a
2
256
p_A=\frac{ a}{2^{256}}
pA=2256a ,
p
B
=
1
−
a
2
256
p_B=\frac{1-a}{2^{256}}
pB=22561−a,挖到矿的人挖下一块矿的概率提升
w
w
w ,求挖到
n
n
n 块区块后A拥有区块数的预期。
考察内容
概率与数学期望,猜结论,乘法逆元
结论
答案是
n
∗
a
n*a
n∗a
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mo=998244353;
ll n,w,x,y;
ll ksm(ll a,ll b)
{
ll ans=1;
for(;b;a=a*a%mo,b>>=1)if(b&1)
ans=ans*a%mo;
return ans;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
cin>>n>>w>>x>>y;
cout<<n*x%mo*ksm(y,mo-2)%mo<<endl;
}
E题 Eyjafjalla / 艾雅法拉冰川火山
题目大意
给定一个以 1 为根的树,孩子的点权小于父亲的点权。
q
q
q 次询问,每次询问包含
x
x
x 节点的权值范围为
[
l
,
r
]
[l, r]
[l,r] 的极大连通块的大小
考察内容
倍增,可持久化线段树
分析
• 每次询问可以看作两个阶段,第一阶段先往上搜索能到达的最高的节点 p,第二阶段查询 p 的子树中所有点权大于
l
l
l 的节点个数。
• 第一阶段可以通过倍增法求得
p
p
p;
• 第二阶段相当于在
p
p
p 的子树中查询权值大于
l
l
l 的节点个数,根据每个节点的 dfs 序建立可持久化线段树。先把
q
q
q 次询问按
l
l
l 的大小排序(离线),然后在线段树上查询。
• 时间复杂度 O ( n l o g n ) O(n log n) O(nlogn) 。
#include<bits/stdc++.h>
using namespace std;
#define MAX 100009
#define cer(x) cerr<<(#x)<<" = "<<(x)<<'\n'
int n,q;
vector<int> E[MAX];
int t[MAX],ord[MAX];
int fa[19][MAX];
int fir[MAX],sec[MAX];
void DFS(int u){
fir[u]=++fir[0];
for(int j=1;j<=17;++j) fa[j][u]=fa[j-1][fa[j-1][u]];
for(int v:E[u]){
if(v==fa[0][u]) continue;
fa[0][v]=u;
DFS(v);
}
sec[u]=fir[0];
}
int ans[MAX];
struct query{
int x,l,r,id;
inline void Get(int i){
scanf("%d%d%d",&x,&l,&r);
id=i;
}
bool operator <(const query& A) const {return l>A.l;}
}Q[MAX];
int sum[MAX];
inline void add(int x){
for(int i=x;i<=n;i+=(i&-i)) sum[i]++;
}
inline int Query(int x){
int ans=0;
for(int i=x;i>=1;i-=(i&-i)) ans+=sum[i];
return ans;
}
signed main(){
scanf("%d",&n);
for(int i=1;i<n;++i){
int x,y;scanf("%d%d",&x,&y);
E[x].push_back(y);
E[y].push_back(x);
}
for(int i=1;i<=n;++i){
scanf("%d",t+i);
}
DFS(1);
scanf("%d",&q);
for(int i=1;i<=q;++i) Q[i].Get(i);
for(int i=1;i<=n;++i) ord[i]=i;
sort(ord+1,ord+n+1,[](int a,int b){return t[a]>t[b];});
sort(Q+1,Q+q+1);
for(int i=1,j=1;i<=q;++i){
while(j<=n&&t[ord[j]]>=Q[i].l) add(fir[ord[j++]]);
int u=Q[i].x;
if(Q[i].r<t[u]||Q[i].l>t[u]) {ans[Q[i].id]=0;continue;}
for(int k=17;k>=0;--k){
if(fa[k][u]&&t[fa[k][u]]<=Q[i].r) u=fa[k][u];
}
ans[Q[i].id]=Query(sec[u])-Query(fir[u]-1);
}
for(int i=1;i<=q;++i) cout<<ans[i]<<'\n';
}