2020牛客暑期多校训练营(第十场)

比赛链接

A Permutation

打了个表,发现一直乘 $2$,不行就乘 $3$,然后继续一直乘 $2$……

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
#include<bits/stdc++.h>

using namespace std;

template<typename T>void read(T&x){x=0;int fl=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')
fl=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}x*=fl;}
template<typename T,typename...Args>inline void read(T&t,Args&...args){read(t);read(args...);}

typedef long long LL;
typedef vector<int> vi;
typedef pair<int, int> pii;
#define mp(x, y) make_pair(x, y)
#define pb(x) emplace_back(x)

const int N = 1000005;

int T, p;

int main(){
for(read(T); T; T--){
read(p);
int now = 1;
vi ans; bool ok = true;
vector<bool> b(p);
ans.pb(now); b[now] = true;
while(ans.size() < p - 1){
if(b[now*2% p] && b[now*3%p]){
ok = false; break;
}
if(b[now*2%p]) now = now*3%p;
else now = now*2%p;
ans.pb(now); b[now] = true;
}
if(!ok) puts("-1");
else{
for(auto &k : ans) printf("%d ", k);
puts("");
}
}
return 0;
}

E Game

二分答案,把大于二分的答案的列往右推。

事实上,再进一步思考的话可以发现,答案就是 $\max\left\{\left\lceil\frac{\sum_{i=1}^ka_i}{k}\right\rceil\right\}$.

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
#include<bits/stdc++.h>

using namespace std;

template<typename T>void read(T&x){x=0;int fl=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')
fl=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}x*=fl;}
template<typename T,typename...Args>inline void read(T&t,Args&...args){read(t);read(args...);}

typedef long long LL;
typedef vector<int> vi;
typedef pair<int, int> pii;
#define mp(x, y) make_pair(x, y)
#define pb(x) emplace_back(x)

const int N = 100005;

int T, n, a[N], b[N];

bool check(int h){
LL vacant = 0, extra = 0;
for(int i = 1; i <= n; i++) b[i] = a[i];
for(int i = n; i >= 1; i--){
if(b[i] <= h) continue;
int pt = i;
while(pt >= 1){
if(b[pt] <= h) vacant += h - b[pt];
else extra += b[pt] - h;
if(extra <= vacant){
extra = 0, vacant = 0;
break;
}
pt--;
}
if(pt == 0) return false;
i = pt;
}
return true;
}

int main(){
for(read(T); T; T--){
read(n);
int l = 1, r = 0;
for(int i = 1; i <= n; i++){
read(a[i]);
r = max(r, a[i]);
}
while(l < r){
int mid = 1ll * (l + r) / 2;
if(check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", l);
}
return 0;
}

J Identical Trees

设 $dp[i][j]$ 表示第一棵树的以 $i$ 节点为根的子树和第二棵树的以 $j$ 节点为根的子树的最少更改次数,转移时考虑所有子节点的匹配,就是一个二分图最大权匹配问题。

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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include<bits/stdc++.h>

using namespace std;

template<typename T>void read(T&x){x=0;int fl=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')
fl=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}x*=fl;}
template<typename T,typename...Args>inline void read(T&t,Args&...args){read(t);read(args...);}

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> vi;
typedef pair<int, int> pii;
#define mp(x, y) make_pair(x, y)
#define pb(x) emplace_back(x)

const int N = 2005;
const int M = 1000005;
const LL INF = 1e14;

bool notP[N];
int pList[N], pID;
void Euler(int n){
notP[0] = notP[1] = 1;
for(int i = 1; i <= n; i++){
if(!notP[i]) pList[++pID] = i;
for(int j = 1; j <= pID; j++){
if(1ll * i * pList[j] > n) break;
notP[i * pList[j]] = 1;
if(i % pList[j] == 0) break;
}
}
}

namespace KM{
int n;
LL w[N][N];
int matchx[N], matchy[N];
LL lx[N], ly[N];
LL slack[N];
bool visx[N], visy[N];

queue<int> q;
int pre[N];

bool check(int cur){
visy[cur] = true;
if(matchy[cur]){
if(!visx[matchy[cur]]){
q.push(matchy[cur]);
visx[matchy[cur]] = true;
}
return false;
}
while(cur) swap(cur, matchx[matchy[cur] = pre[cur]]);
return true;
}
void bfs(int s){
fill(visx, visx+n+1, false);
fill(visy, visy+n+1, false);
fill(slack, slack+n+1, INF);
while(!q.empty()) q.pop();
q.push(s), visx[s] = true;
while(1){
while(!q.empty()){
int cur = q.front(); q.pop();
for(int i = 1; i <= n; i++){
LL diff = lx[cur] + ly[i] - w[cur][i];
if(!visy[i] && diff <= slack[i]){
slack[i] = diff;
pre[i] = cur;
if(diff == 0)
if(check(i)) return;
}
}
}
LL delta = INF;
for(int i = 1; i <= n; i++)
if(!visy[i] && slack[i])
delta = min(delta, slack[i]);
for(int i = 1; i <= n; i++){
if(visx[i]) lx[i] -= delta;
if(visy[i]) ly[i] += delta;
else slack[i] -= delta;
}
while(!q.empty()) q.pop();
for(int i = 1; i <= n; i++)
if(!visy[i] && !slack[i] && check(i))
return;
}
}
void solve(){
fill(matchx, matchx+n+1, 0);
fill(matchy, matchy+n+1, 0);
fill(ly, ly+n+1, 0);
for(int i = 1; i <= n; i++){
lx[i] = 0;
for(int j = 1; j <= n; j++)
lx[i] = max(lx[i], w[i][j]);
}
for(int i = 1; i <= n; i++) bfs(i);
}
}

int n, fax[N], fay[N], rtx, rty;
vi edgex[N], edgey[N];

int szx[N], szy[N];
ULL valx[N], valy[N];
void dfs(int x, vi edge[], int sz[], ULL val[]){
sz[x] = 1, val[x] = 1;
for(auto &to : edge[x]){
dfs(to, edge, sz, val);
sz[x] += sz[to];
val[x] += pList[sz[to]] * val[to];
}
}

LL dp[N][N];
LL solve(int x, int y){
if(valx[x] != valy[y]) return INF;
if(dp[x][y] != -1) return dp[x][y];
dp[x][y] = x != y;
int sz = edgex[x].size();
if(sz == 0) return dp[x][y];
for(int i = 0; i < sz; i++)
for(int j = 0; j < sz; j++)
dp[edgex[x][i]][edgey[y][j]] = solve(edgex[x][i], edgey[y][j]);
KM::n = sz;
for(int i = 1; i <= sz; i++)
for(int j = 1; j <= sz; j++)
KM::w[i][j] = -INF;
for(int i = 0; i < sz; i++)
for(int j = 0; j < sz; j++)
KM::w[i+1][j+1] = -dp[edgex[x][i]][edgey[y][j]];
KM::solve();
for(int i = 1; i <= sz; i++) dp[x][y] += -KM::w[i][KM::matchx[i]];
return dp[x][y];
}

int main(){
memset(dp, -1, sizeof dp);
Euler(2000);
read(n);
for(int i = 1; i <= n; i++){
read(fax[i]);
if(!fax[i]) rtx = i;
else edgex[fax[i]].pb(i);
}
for(int i = 1; i <= n; i++){
read(fay[i]);
if(!fay[i]) rty = i;
else edgey[fay[i]].pb(i);
}
dfs(rtx, edgex, szx, valx), dfs(rty, edgey, szy, valy);
printf("%lld\n", solve(rtx, rty));
return 0;
}
作者

xyfJASON

发布于

2020-08-10

更新于

2021-08-28

许可协议

评论