Codeforces Round #720 (Div. 2) 题解
https://codeforces.com/contest/1521
C起码该出的,结果比赛时凌乱了,我是fw。
参考洛绫璃
A题
题意:
给你两个数A,B,定义一个数满足\(x mod (A * B) = 0\)是好的数,否则只满足\(x mod A = 0\)是近似好的数,
让你构造三个各不相同的数x,y,z满足,只有一个是好的数,其它两个是近似好的数,且\(x + y = z\)
思路:
注意到 \(gcd(x, x + 1) = 0\), 构造\(a + (b - 1) = a * b\)即可
注意b = 2时,前两项相等,因此把b扩大一倍即可。
ll a, b;
int main()
{
IOS;
int T;
cin >> T;
while(T --)
{
cin >> a >> b;
if(b == 1) cout << "NO\n";
else
{
cout << "YES\n";
b = b * 2;
cout << a << " " << (b - 1) * a << " " << a * b << endl;
}
}
return 0;
}
B题
题意:
给你一个数组a,允许你进行操作选定两个下标i, j,
满足\(min(a_i, a_j) = min(x, y)\),即可将对应的数变成x,y。
思路:
注意到 \(gcd(x, x + 1) = 0\)
因此找到最小的数,然后往左右两边不断 + 1构造即可。
ll n;
ll a[N];
struct node{
int i, j, x, y;
};
vector<node> v;
int main()
{
IOS;
int T;
cin >> T;
while(T --)
{
v.clear();
cin >> n;
int mind = 1e9 + 10, d;
for(int i = 1 ; i <= n ; i ++)
{
cin >> a[i];
if(mind > a[i])
{
mind = a[i];
d = i;
}
}
int x = mind;
for(int i = d + 1 ; i <= n ; i ++)
v.push_back({d, i, mind, ++ x});
x = mind;
for(int i = d - 1 ; i >= 1 ; i --)
v.push_back({i, d, ++ x, mind});
cout << v.size() << "\n";
for(auto x : v)
cout << x.i << " " << x.j << " " << x.x << " " << x.y << "\n";
}
return 0;
}
C题
题意:
交互题,支持下图询问,然你猜出整个数组(该数组是一个1到n的排列)
思路:
用 \(n / 2\)次找到1,然后用n次确定所有其他数,因此花费\((n * 3) / 2\)次
int a[N];
int n;
int ask(int x, int y, int z, bool f)
{
if (!f) cout << "? 1 " << x << ' ' << y << ' ' << z << endl;
else cout << "? 2 " << x << ' ' << y << ' ' << z << endl;
cin >> x; return x;
}
int main()
{
IOS;
int T;
cin >> T;
while(T --)
{
cin >> n;
int id;
for(int i = 1 ; i <= n ; i += 2)
{
if(i + 1 <= n)
{
int c = ask(i, i + 1, 1, 1);
if(c == 1)
{
a[i] = 1;
id = i;
break;
}
else if(c == 2 && ask(i + 1, i, 1, 1) == 1)
{
a[i + 1] = 1;
id = i + 1;
break;
}
}
else
{
id = i;
a[i] = 1;
break;
}
}
for(int i = 1 ; i <= n ; i ++)
if(id ^ i) a[i] = ask(id, i, n - 1, 0);
cout << "! ";
for(int i = 1 ; i <= n ; i ++) cout << a[i] << " ";
cout << endl;
}
return 0;
}
D题
题意:
给你一棵树,每次可以删一条边然后加一条边,问你最少操作多少次可以把树变成一条链
输出操作方案
思路:
dfs遍历, 然后根据儿子数目情况操作,详情见如下代码
int n;
vector<pii> v1, v2;
int h[N], e[M], ne[M], idx;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int dfs(int u, int fa)
{
int l = 0, r = 0;
for(int i = h[u] ; ~i ; i = ne[i])
{
int j = e[i];
if(j == fa) continue;
int cur = dfs(j, u); //当前儿子所处的子树是否还有能连边的节点
if(!cur) continue;
//如果已经有两个儿子,就直接把边切了
if(r) v1.push_back({u, j}), v2.push_back({j, cur});
else if(!l) l = cur;
else if(!r) r = cur;
}
//如果有父亲,两个儿子,就把和父亲的边切了,然后把两个儿子放进v2
if(l && r && fa)
v1.push_back({fa, u}), v2.push_back({l, r});
// return l ? (r && fa) ? 0 : l : u;
if(l)
{
if(r && fa) return 0; //和父亲的边被切掉了
else return l; //有左儿子返回左儿子
}
return u; //当前结点没有左右儿子了
}
int main()
{
IOS;
int T;
cin >> T;
while(T --)
{
cin >> n;
idx = 0;
for(int i = 1 ; i <= n ; i ++) h[i] = -1;
for(int i = 1 ; i < n ; i ++)
{
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
int m = dfs(1, 0);
cout << v1.size() << "\n";
for(int i = 0 ; i < v1.size() ; ++ i)
cout << v1[i].x << " " << v1[i].y << " " << m << " " << v2[i].x << "\n", m = v2[i].y;
v1.clear(), v2.clear();
}
return 0;
}
/*
1
7
1 2
1 3
1 4
1 5
5 6
5 7
*/