2021.10.19 模拟赛题解
T1
注意到每条边我们不用关心 \(u,v\) 具体是什么,只用关心它们中间相隔了多少个点,设为 \(d\)
将边按照边权大小排序,然后动态枚举图中连通块个数,初始为 \(n\),每次设 \(n'=\gcd(n,d)\),答案加上 \((n-n')·w\),其中 \(w\) 为边权,然后令 \(n\leftarrow n'\) 即可。
时间复杂度 \(m\log m\)。
T2
首先根据经典结论:一个排列需要进行的冒泡排序轮数,等于在每个元素之前比每个元素大的元素个数的最大值。
考虑对于一个需要冒泡排序轮数为 \(d\) 的排列,我们在 \(1,2,3,\cdots,d\) 处计算该排列的贡献,于是问题转化为,有多大概率,存在一个元素,其之前比它大的元素个数 \(\ge d\)。
再考虑容斥,拿 \(1\) 减去不存在任何元素,其之前比它大的元素个数 \(\ge d\) 的概率,我们考虑从大到小插入元素,那么对于 \(i<d\),第 \(i\) 个插入的元素有 \(i\) 个可能的位置,而后面插入的位置都有 \(d\) 个可能的位置,因此总概率就是 \(d!·d^{n-d}·\dfrac{1}{n!}\)。
故
T3
赛时非常 sb 的一步没想到,萎了
首先将 \(k\) 次方转化为对每个 \(k\) 元组计算答案。
所以我们复杂度无比优秀的 \(n^k\) 的神必算法都可以拿到 70 分的好成绩
\(k=1\) 的情况不多说,直接枚举每个点统计有多少个矩形包含这个点即可。
\(k=2\) 的情况仿照树状数组统计逆序对的套路,对于 \(i<j\) 的两点 \(i,j\),我们分 \(p_i<p_j\) 和 \(p_i>p_j\) 两部分分类讨论,而两部分都可以将 \(i,j\) 的贡献独立开来,BIT 维护即可。
\(k=3\) 的情况我们要对每三点统计贡献,三个点都落在同一个点的情况直接跑一遍 \(k=1\) 即可,三个点中有两个本质不同的点的情况跑一遍 \(k=2\) 即可,重点是三个点都不同的情况,画个图可以发现有六种可能的位置关系:
X.. ..X .X. .X. ..X X..
.X. .X. X.. X.. X.. ..X
..X X.. ..X ..X .X. .X.
显然前两种可通过旋转重合,后四种可通过旋转重合,因此我们只用考虑第一种和第三种即可。第一种的处理方式非常 trivial:枚举中间点,然后前后各一遍 BIT 维护左边的 X 和右边的 X 的贡献。
比较麻烦的是第三种情况,我们考虑这样一个扫描线的过程:维护两个数组 \(v,s\),从小到达加入元素,当我们扫到第一个点(也就是第二排第一个 X)时,令 \(v_{p_i}=i\),当我们扫到第二个点(也就是第一排第二个 X)时,令所有 \(j\ge p_i\) 的 \(s_j\) 加上 \(v_j·p_i\),当我们扫到第三个点(也就是第三排第三个 X)时,我们加入这三个 X 的贡献,即统计一遍 \(\sum\limits_{j=1}^is_j\),将 \(\sum\limits_{j=1}^is_j·(n-j+1)·(n-p_j+1)\),用线段树维护这个过程即可。
时间复杂度 \(n\log n\)。
const int MAXN=1e5;
const int MOD=998244353;
int n,k,p[MAXN+5];
namespace solve_one{
int solve(){
int res=0;
for(int i=1;i<=n;i++) res=(res+1ll*i*p[i]%MOD*(n-i+1)%MOD*(n-p[i]+1))%MOD;
return res;
}
}
namespace solve_two{
struct fenwick_tree{
int t[MAXN+5];
void add(int x,int v){for(int i=x;i<=n;i+=(i&(-i))) (t[i]+=v)%=MOD;}
int query(int x){int ret=0;for(int i=x;i;i&=(i-1)) (ret+=t[i])%=MOD;return ret;}
} t1,t2;
int solve(){
int res=0;
for(int i=1;i<=n;i++){
res=(res+1ll*(n-i+1)*(n-p[i]+1)%MOD*t1.query(p[i]-1))%MOD;
res=(res+1ll*(n-i+1)*p[i]%MOD*t2.query(n-p[i]))%MOD;
t1.add(p[i],1ll*i*p[i]%MOD);t2.add(n-p[i]+1,1ll*i*(n-p[i]+1)%MOD);
}
return res;
}
}
namespace solve_three{
struct node{int l,r,lz,sum1,sum2;} s[MAXN*4+5];
void pushup(int k){
s[k].sum1=(s[k<<1].sum1+s[k<<1|1].sum1)%MOD;
s[k].sum2=(s[k<<1].sum2+s[k<<1|1].sum2)%MOD;
}
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;s[k].lz=s[k].sum1=s[k].sum2=0;if(l==r) return;
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void tag(int k,int v){
s[k].lz=(s[k].lz+v)%MOD;
s[k].sum2=(s[k].sum2+1ll*s[k].sum1*v)%MOD;
}
void pushdown(int k){if(s[k].lz) tag(k<<1,s[k].lz),tag(k<<1|1,s[k].lz),s[k].lz=0;}
void makemul(int k,int l,int r,int v){
if(l<=s[k].l&&s[k].r<=r) return tag(k,v),void();
pushdown(k);int mid=s[k].l+s[k].r>>1;
if(r<=mid) makemul(k<<1,l,r,v);
else if(l>mid) makemul(k<<1|1,l,r,v);
else makemul(k<<1,l,mid,v),makemul(k<<1|1,mid+1,r,v);
pushup(k);
}
int query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return s[k].sum2;
pushdown(k);int mid=s[k].l+s[k].r>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return (query(k<<1,l,mid)+query(k<<1|1,mid+1,r))%MOD;
}
void modify(int k,int p,int v){
if(s[k].l==s[k].r) return s[k].sum1=v,void();
pushdown(k);int mid=s[k].l+s[k].r>>1;
(p<=mid)?modify(k<<1,p,v):modify(k<<1|1,p,v);
pushup(k);
}
struct fenwick_tree{
int t[MAXN+5];
void add(int x,int v){for(int i=x;i<=n;i+=(i&(-i))) (t[i]+=v)%=MOD;}
int query(int x){int ret=0;for(int i=x;i;i&=(i-1)) (ret+=t[i])%=MOD;return ret;}
} t1,t2;
int pre1[MAXN+5],pre2[MAXN+5],suf1[MAXN+5],suf2[MAXN+5];
int solve(){
int res=0;
for(int i=1;i<=n;i++){
pre1[i]=t1.query(p[i]-1);
pre2[i]=t2.query(n-p[i]);
t1.add(p[i],1ll*i*p[i]%MOD);
t2.add(n-p[i]+1,1ll*i*(n-p[i]+1)%MOD);
} memset(t1.t,0,sizeof(t1.t));
memset(t2.t,0,sizeof(t2.t));
for(int i=n;i;i--){
suf1[i]=t1.query(p[i]-1);
suf2[i]=t2.query(n-p[i]);
t1.add(p[i],1ll*(n-i+1)*p[i]%MOD);
t2.add(n-p[i]+1,1ll*(n-i+1)*(n-p[i]+1)%MOD);
}
for(int i=1;i<=n;i++){
res=(res+1ll*pre1[i]*suf2[i])%MOD;
res=(res+1ll*pre2[i]*suf1[i])%MOD;
}
for(int _=0;_<4;_++){
build(1,1,n);
for(int i=1;i<=n;i++){
res=(res+1ll*query(1,1,p[i])*(n-i+1)%MOD*(n-p[i]+1))%MOD;
makemul(1,p[i],n,p[i]);modify(1,p[i],i);
}
if(~_&1) reverse(p+1,p+n+1);
else if(_==1){for(int i=1;i<=n;i++) p[i]=n+1-p[i];}
}
return res;
}
}
int main(){
freopen("points.in","r",stdin);
freopen("points.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
if(k==1) printf("%d\n",solve_one::solve());
else if(k==2) printf("%d\n",(solve_one::solve()+2ll*solve_two::solve())%MOD);
else printf("%d\n",(solve_one::solve()+6ll*solve_two::solve()+6ll*solve_three::solve())%MOD);
return 0;
}
T4
什 么?你 确 定 EI 的 T4 是 给 人 补 的?
题解看到求 \(\sum\limits_{i=0}^{m-1}k^i\bmod p^{\alpha}\) 这里就实在看不下去了,就不补了(

浙公网安备 33010602011771号