10.04 模拟赛 by FXT

10.04 模拟赛

抵制打包,抵制打包,抵制打包!

T1

JOISC 2022 D3T2 Sprinkler

https://loj.ac/p/3692

Solution

观察到模数不是质数,像点分树一样,如果到这个点的意义是距离小于等于这个点 $d$ 乘上 $x$,把距离这个点为 $d,d-1$ 的打上标记,然后往上继续做。观察到如果一个点在范围里,那么有且仅有会被乘上一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define maxn 400505
#define put() putchar('\n')
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
using namespace std;
void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug((char*)#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
#define fi first
#define se second
#define mk make_pair
int mod;
int power(int x,int y=mod-2) {
int sum=1;
while (y) {
if (y&1) sum=sum*x%mod;
x=x*x%mod;y>>=1;
}
return sum;
}
int n,p;
int fa[maxn];
vector<int>to[maxn];
int w[maxn][41];
void dfs1(int x,int pre) {
fa[x]=pre;
for (auto y:to[x]) if (y^pre) {
dfs1(y,x);
}
}
signed main(void){
int i,x,y,op,val,d,j,q;
read(n);read(mod);
for (i=1;i<n;i++) {
read(x),read(y);
to[x].push_back(y);
to[y].push_back(x);
}
to[n+1].push_back(1);
for (i=n+2;i<=n+40;i++) to[i].push_back(i-1);
int root=n+40;
for (i=1;i<=root;i++) for (j=0;j<=40;j++) w[i][j]=1;
for (i=1;i<=n;i++) read(w[i][0]);
dfs1(root,0);
read(q);
while (q--) {
read(op);read(x);
if (op==1) {
read(d);read(val);
int dis=0,res=d;
for (x;res>=0;dis++,x=fa[x]) {
w[x][res]=w[x][res]*val%mod;
if (res) w[x][res-1]=w[x][res-1]*val%mod;
res--;
}
}
else {
int ans=1,dis=0;
for (;dis<=40;dis++,x=fa[x]) ans=ans*w[x][dis]%mod;
printf("%lld\n",ans);
}
}
return 0;
}

T2

JOISC 2023 D4T3 Bitaro’s travel QOJ 6343

Solution

观察到如果拐一次弯,那么走过的区间长度至少乘 $2$,所以转弯次数是 $O(\log v)$ 次的。

然后我们就想到怎么暴力找到拐弯的地方。令 $r_x$ 表示如果区间左端点在 $x$,右端点最多在 $r_x$ 时,都往右边走。然后每次枚举转向二分一下就好了。区间询问 $r$ 预处理出来。向左也是一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define maxn 200005
#define put() putchar('\n')
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
using namespace std;
void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug((char*)#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
#define fi first
#define se second
#define mk make_pair
const int mod=1e9+7;
int power(int x,int y=mod-2) {
int sum=1;
while (y) {
if (y&1) sum=sum*x%mod;
x=x*x%mod;y>>=1;
}
return sum;
}
int n,a[maxn],lg[maxn];
int q;
int fr[maxn][21],rs[maxn];
int fl[maxn][21],ls[maxn];
int queryr(int l,int r) {
if (l>r) return -1e9;
int z=lg[r-l+1];
return max(fr[l][z],fr[r-(1<<z)+1][z]);
}
int queryl(int l,int r) {
if (l>r) return 1e9;
int z=lg[r-l+1];
return min(fl[l][z],fl[r-(1<<z)+1][z]);
}
signed main(void){
int i,j,x,pus;
read(n);
for (i=1;i<=n;i++) read(a[i]);a[0]=-1e10,a[n+1]=1e10;
for (i=2;i<=n;i++) {
rs[i]=lower_bound(a+1,a+1+n,a[i]+a[i]-a[i-1])-a-1;
fr[i][0]=rs[i];
}
for (i=1;i<n;i++) {
ls[i]=lower_bound(a+1,a+1+n,a[i]-(a[i+1]-a[i]))-a;
fl[i][0]=ls[i];
}
for (j=1;j<=20;j++) {
for (i=1;i+(1<<j)-1<=n;i++) {
fr[i][j]=max(fr[i][j-1],fr[i+(1<<j-1)][j-1]);
fl[i][j]=min(fl[i][j-1],fl[i+(1<<j-1)][j-1]);
}
}
for (i=2;i<=n;i++) lg[i]=lg[i/2]+1;
read(q);
while (q--) {
read(pus);
if (n==1) {
printf("%lld\n",abs(a[1]-pus));
continue;
}
x=lower_bound(a+1,a+1+n,pus)-a;
int ans=0,l=x,r=x,flag=0;
if (pus==a[x]) {
if (a[x]-a[x-1]<=a[x+1]-a[x]) l=x-1,r=x,ans=pus-a[x-1],flag=1;
else l=x,r=x+1,ans=a[x+1]-a[x],flag=0;
}
else if (pus-a[x-1]<=a[x]-pus) l=r=x-1,ans=pus-a[x-1],flag=1;
else l=r=x,ans=a[x]-pus,flag=0;
while (l>1||r<n) {
if (l==1) {
if (flag) ans+=a[n]-a[1];
else ans+=a[n]-a[r];
break;
}
if (r==n) {
if (flag) ans+=a[l]-a[1];
else ans+=a[n]-a[1];
break;
}
if (flag) {
int L=0,R=l+1,mid;
while (L+1<R) {
int mid=L+R>>1;
if (queryr(mid+1,l)>r) L=mid;
else R=mid;
}
ans+=a[l]-a[R]+a[r+1]-a[R];
l=R,r++;flag^=1;
}
else {
int L=r-1,R=n+1,mid;
while (L+1<R) {
int mid=L+R>>1;
if (queryl(r,mid-1)<l) R=mid;
else L=mid;
}
ans+=a[L]-a[r]+a[L]-a[l-1];
r=L,l--,flag^=1;
}
}
printf("%lld\n",ans);
}
return 0;
}

后记

今天 T2 100->20 的原因是 $n=1$ 判挂了,之前改读入变量之后忘记再改特判了。

从自身的角度想,没有再测一遍样例,是我太懒了。

但从这个 jb 赛制的角度想,如果不是打包,那么 $n=1$ 的点最多最多一两个吧,分数也是可观的。

T3

JOI Open 2018 T1 Bubble Sort 2 QOJ 2643

Solution

令 $d_i$ 表示 $\sum_{j<i} [a_j>a_i]$ 的值,则冒泡排序的次数就是 $\max d_i$。

先钦定所有数都是不同的。如果存在数值相同的点选标号最大的那个就行。

观察到答案一定在下凸包上,令点 $x$ 是其中的一个点,则 $d_x=x-\sum_{1\le j\le n} [a_j<a_x]$ 。

而如果答案不在下凸包上,$d_x>x-\sum_{1\le j\le n} [a_j<a_x]$,因为可能减掉标号比 $x$ 大的点。但是无关紧要,即使右边等于左边,他也不能作为答案,

所以只需要维护每个值的 $d_x=x-\sum_{1\le j\le n} [a_j<a_x]$ 的最大值即可。用权值线段树,复杂度 $O(n\log n)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define maxn 1000005
#define put() putchar('\n')
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
using namespace std;
void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug((char*)#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
#define fi first
#define se second
#define mk make_pair
const int mod=1e9+7;
int power(int x,int y=mod-2) {
int sum=1;
while (y) {
if (y&1) sum=sum*x%mod;
x=x*x%mod;y>>=1;
}
return sum;
}
int n,q,a[maxn];
int d[maxn];
#define lowbit(x) ((x)&(-x))
struct node {
int ls,rs,Max,lazy,siz;
}f[10000005];
int cnt=1,root=1,tot;
pair<int,int>o[maxn];
set<int>t[maxn];
int g[maxn];
const int inf=1e9;
void pushup(int rt) {
f[rt].Max=max(f[f[rt].ls].Max,f[f[rt].rs].Max);
}
void pushdown(int rt) {
if (f[rt].lazy) {
int k=f[rt].lazy;f[rt].lazy=0;
f[f[rt].ls].lazy+=k,f[f[rt].rs].lazy+=k;
f[f[rt].ls].Max+=k,f[f[rt].rs].Max+=k;
}
}
void modify(int l,int r,int &rt,int head,int k,int siz) {
if (!rt) rt=++cnt,f[rt].Max=-inf,f[rt].lazy=0,f[rt].siz=0;
f[rt].siz+=siz;
if (l==r) {
f[rt].Max=k;
return ;
}
int mid=l+r>>1;pushdown(rt);
if (head<=mid) modify(l,mid,f[rt].ls,head,k,siz);
else modify(mid+1,r,f[rt].rs,head,k,siz);
pushup(rt);
}
void Update(int l,int r,int &rt,int head,int tail,int k) {
if(head>tail) return ;
if (!rt) rt=++cnt,f[rt].Max=-inf,f[rt].lazy=0,f[rt].siz=0;
if (head<=l&&r<=tail) return f[rt].Max+=k,f[rt].lazy+=k,void();
int mid=l+r>>1;pushdown(rt);
if (head<=mid) Update(l,mid,f[rt].ls,head,tail,k);
if (tail>mid) Update(mid+1,r,f[rt].rs,head,tail,k);
pushup(rt);
}
int Query(int l,int r,int rt,int head,int tail) {
if (!rt) return 0;
if (head<=l&&r<=tail) return f[rt].siz;
int mid=l+r>>1,sum=0;pushdown(rt);
if (head<=mid) sum+=Query(l,mid,f[rt].ls,head,tail);
if (tail>mid) sum+=Query(mid+1,r,f[rt].rs,head,tail);
return sum;
}
int query(int l,int r,int rt,int head,int tail) {
if (!rt) return 0;
if (head<=l&&r<=tail) return f[rt].Max;
int mid=l+r>>1,sum=0;pushdown(rt);
if (head<=mid) sum+=query(l,mid,f[rt].ls,head,tail);
if (tail>mid) sum+=query(mid+1,r,f[rt].rs,head,tail);
return sum;
}
signed main(void){
int i,x,y,j,tmp,ans;
read(n);read(q);
for (i=1;i<=n;i++) read(a[i]);
f[0].Max=-inf;
tot=0;
for (i=1;i<=n;i++) g[++tot]=a[i];
for (i=1;i<=q;i++) {
read(x),read(y),x++,o[i]=mk(x,y);
g[++tot]=y;
}
sort(g+1,g+1+tot);
tot=unique(g+1,g+1+tot)-g-1;
for (i=1;i<=n;i++) {
a[i]=lower_bound(g+1,g+1+tot,a[i])-g;
t[a[i]].insert(i);
modify(1,tot,root,a[i],-inf,1);
}
for (i=1;i<=n;i++) {
modify(1,tot,root,a[i],i-Query(1,tot,1,1,a[i]),0);
}
for (i=1;i<=q;i++) {
x=o[i].fi,y=o[i].se;
y=lower_bound(g+1,g+1+tot,y)-g;
t[a[x]].erase(x);
modify(1,tot,root,a[x],-inf,-1);
if (t[a[x]].begin()!=t[a[x]].end()) {
int tmp=*(--t[a[x]].end());
modify(1,tot,root,a[x],tmp-Query(1,tot,1,1,a[x]),0);
}
Update(1,tot,root,a[x]+1,tot,1);

a[x]=y;
t[a[x]].insert(x);
modify(1,tot,root,a[x],-inf,1);
int tmp=*(--t[a[x]].end()),z=tmp-Query(1,tot,1,1,a[x]);
modify(1,tot,root,a[x],tmp-Query(1,tot,1,1,a[x]),0);
Update(1,tot,root,a[x]+1,tot,-1);
printf("%d\n",max(1,f[1].Max));
}
return 0;
}

T4

CF1804H Code Lock

感觉是高端搜索。

不会。