比赛过程
这第十场有点自闭,前面手速满了,签到题没有尽快写出来,还是太过犹豫。
题解
A
题意
给出 n,求长度为n-1的permutation,要求对于每个i都有pi+1=2p(mod p)或pi+1=3p(mod p)
解法
就是随便取一个数开头,每次能乘 2 就乘 2 不行就乘 3。题解解释就是考虑x向 x ∗ 2 x*2 x∗2连边,那么形成了若干个环,并且同一个环内的数 ∗ 3 *3 ∗3 会同时连向另外同一个环。
代码
int main(){
IO;
int T;
cin >> T;
while(T--){
int p;
cin >> p;
ll now = 1;
int f = 1;
map<int, int> mp;
vector<int> ans;
mp[now] = 1;
ans.push_back(1);
FOR(i,1,p-2){
if(!mp[now*2%p]) {
now = now * 2 % p;
mp[now] = 1;
ans.push_back(now);
}
else if(!mp[now*3%p]){
now = now * 3 % p;
mp[now] = 1;
ans.push_back(now);
}
else
f = 0;
}
if(f){
for(auto i:ans){
cout << i << " ";
}
}
else
cout << -1;
cout << endl;
}
return 0;
}
E
题意
解法
这个真就猜呗,说实话我也证明不出来,题解也就这么一句话,二分还是稳,但我选择直接猜一手最大前缀平均值。其实当时比赛写烦了,其实不用开数组。
代码
ll a[maxn];
int main()
{
IO;
int t;
cin >> t;
while (t--)
{
ll sum = 0;
int n;
cin >> n;
ll ma = 0;
re(i, 1, n)
{
cin >> a[i];
sum += a[i];
ll te=sum/i+(sum%i!=0);
ma = max(ma, te);
}
cout << ma << endl;
}
}
J
题意
给定两个均含有n个节点的树T1,T2,每个节点的权值在1~n范围内。如果这两个树满足:树根的权值相同;对于任意非根节点,其父节点权值也应相同。现在你要改变T1的节点权值使得T1=T2,问最少需要改变的节点数。
解法
dp[x][y]表示以左边的树x为根,右边的树y为根,他们有dp[x][y]个序号是重合的,若x和y不同构那就dp[x][y] = -INF;
第一步利用get函数获得每一种树的形式编号,tot1[x] = tot2[y]就代表x和y同构,
第二步就跑费用流,每次跑都重新建图(删除之前建过的图)
如何转移?
给x的儿子们和y的儿子们建个二分图跑最大权值匹配,跑下来的最大权值就是儿子们的答案。
代码
int n, tot, ans;
// MCMF费用流代码
int head[N], ver[M], nex[M], edge[M], cost[M];
int vis[N], dis[N], incf[N], pre[N];
void init() {
tot = 1;
ms(head, 0);
}
void add(int x, int y, int z, int c) {
ver[++tot] = y, edge[tot] = z, cost[tot] = c, nex[tot] = head[x], head[x] = tot;
ver[++tot] = x, edge[tot] = 0, cost[tot] = -c, nex[tot] = head[y], head[y] = tot;
}
bool spfa(int s, int t) {
queue<int> q;
ms(dis, inf), ms(vis, 0);
q.push(s), dis[s] = 0, vis[s] = 1;
incf[s] = INF;
while(!q.empty()) {
int x = q.front(); q.pop(); vis[x] = 0;
for(int i = head[x]; i; i = nex[i]) {
int y = ver[i];
if(dis[y] > dis[x] + cost[i] && edge[i]) {
dis[y] = dis[x] + cost[i];
incf[y] = min(incf[x], edge[i]);
pre[y] = i;
if(!vis[y]) vis[y] = 1, q.push(y);
}
}
}
if(dis[t] == INF) return false;
return true;
}
void update(int s, int t, int &flow) {
int x = t;
while(x != s) {
int i = pre[x];
edge[i] -= incf[t], edge[i^1] += incf[t];
x = ver[i ^ 1];
}
flow += incf[t];
ans += dis[t] * incf[t];
}
int solve(int s, int t, int &flow) {
ans = 0;
while(spfa(s, t)) update(s, t, flow);
return ans;
}
// 树上dp
ll dp[550][550];
vector<int>G1[N], G2[N];
map<string, int> id;
int judge[550][550];
int aans = 0, tot1[550], tot2[550];
int dfs(int x, int y) {
// x和y是否同构
if(!judge[x][y]) {
dp[x][y] = -INF;
return 0;
}
if(x == y) {
dp[x][y] = 1;
if(!G1[x].size()) return 0;
}
rep(i, 0, G1[x].size()-1) rep(j, 0, G2[y].size()-1) {
int a = G1[x][i];
int b = G2[y][j];
dfs(a, b);
}
init();
rep(i, 0, G1[x].size() - 1) add(2010, i, 1, 0);
rep(j, 0, G2[y].size() - 1) add(j+505, 2011, 1, 0);
rep(i, 0, G1[x].size() - 1)
rep(j, 0, G2[y].size() - 1) {
int a = G1[x][i];
int b = G2[y][j];
add(i, j+505, 1, -dp[a][b]);
}
int cntt = 0;
int ans = solve(2010, 2011, cntt);
dp[x][y] -= ans;
return 0;
}
void get(int x, int y) {
rep(i, 0, G1[x].size() - 1)
rep(j, 0, G2[y].size() - 1) {
int a = G1[x][i];
int b = G2[y][j];
get(a, b);
}
string str;
if(G1[x].size() == G2[y].size()) {
if(!G1[x].size()) judge[x][y] = 1;
else {
for(auto tmp : G1[x]) str += (char)(tot1[tmp] + '0');
sort(str.begin(), str.end());
if(!id[str]) id[str] = ++aans;
tot1[x] = id[str];
str.clear();
for(auto tmp : G2[y]) str += (char)(tot2[tmp] + '0');
sort(str.begin(), str.end());
if(!id[str]) id[str] = ++aans;
tot2[y] = id[str];
str.clear();
if(tot1[x] == tot2[y]) judge[x][y] = 1;
}
}
}
int main() {
scanf("%d", &n);
int rt1, rt2;
rep(i, 1, n) {
int x; scanf("%d", &x);
if(!x) rt1 = i;
else G1[x].pb(i);
}
rep(i, 1, n) {
int x; scanf("%d", &x);
if(!x) rt2 = i;
else G2[x].pb(i);
}
rep(i, 1, n) dp[i][i] = 1;
get(rt1, rt2);
dfs(rt1, rt2);
printf("%d\n", n - dp[rt1][rt2]);
return 0;
}