nowcoder 2020 多校 第三场
E Two Matchings
题意
可以简化题意为,每个点有个权重$w$,两个点$i,j$相连的代价$abs(w_i-w_j)$,找两个没有重叠的匹配使得代价最小
Solution
其实就是在将数字用长度为偶数的环连起来,求最小代价。进一步可以发现,环用长度为4或6,长度更长的环可以被分解达到更小的代价
LL n;
LL a[MAX];
LL dp[MAX][2];
LL four(const vector<LL> &a){
return 2LL * (a[3]-a[0]);
}
LL six(const vector<LL> &a){
return 2LL * (a[5]-a[0]);
}
int main(){
#ifdef DEBUG
freopen("in", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--)
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> a[i];
sort(a, a+n);
for(LL i = 0; i <= n; i++ )
dp[i][0] = dp[i][1] = __64inf;
dp[3][0] = 2LL * (a[3]-a[0]);
dp[5][0] = 2LL * (a[5]-a[0]);
dp[7][0] = 2LL * (a[7]-a[4] + a[3] - a[0]);
for(LL i = 9; i < n; i+=2){
dp[i][0] = min(dp[i-4][0], dp[i-4][1]) + four(vector<LL>({a[i-3], a[i-2], a[i-1], a[i]}));
dp[i][1] = min(dp[i-6][0], dp[i-6][1]) +
six(vector<LL>({a[i-5], a[i-4], a[i-3], a[i-2], a[i-1], a[i]}));
}
printf("%d\n", min(dp[n-1][0], dp[n-1][1]));
}
}
F Fraction Construction Problem
题意
问有没有满足$\displaystyle\frac{c}{d}-\frac{e}{f}=\frac{a}{b}$的$c,d,e,f$
Solution
感觉是分类讨论,然后构造解
void ex_gcd(LL a, LL b, LL &x, LL &y){
if(b == 0){
x = 1;
y = 0;
return;
}
ex_gcd(b, a % b, x, y);
LL tmp = x;
x = y;
y = tmp - (a / b) * y;
}
LL p[MAX];
LL cnt[MAX];
vector<LL> prime;
bool isprime[MAX];
void init(){
mset(isprime, 1);
isprime[0] = isprime[1] = 0;
for(int i = 2; i < MAX; i++){
if(isprime[i]) {
prime.push_back(i);
cnt[i] = 1;
p[i] = i;
}
for(int j = 0; j < prime.size() and i * prime[j] < MAX; j++){
isprime[i * prime[j]] = 0;
cnt[i * prime[j]] = i % prime[j] == 0 ? cnt[i] : cnt[i] + 1;
p[i * prime[j]] = prime[j];
}
}
}
int main(){
#ifdef DEBUG
#else
ios::sync_with_stdio(0);
cin.tie(0);
#endif
init();
int T;
cin >> T;
while (T--)
{
LL a, b;
cin >> a >> b;
LL g = __gcd(a, b);
if(g > 1){
LL bb = b / g, aa = a / g;
cout << aa + 1 << " " << bb << ' ' << 1 << ' ' << bb << '\n';
continue;
}
LL tmp = b;
if(cnt[b] <= 1) {
cout << "-1 -1 -1 -1\n";
continue;
}
LL d = 1;
tmp = b;
while(tmp % p[b] == 0) {
tmp /= p[b];
d *= p[b];
}
LL f = b / d;
LL c, e;
ex_gcd(f, d, c, e);
if(c < 0) {
LL t = - (c -d + 1) / d;
c += t * d;
e -= t * f;
}
e = -e;
e *= a;
c *= a;
cout << c << ' ' << d << ' ' << e << ' ' << f << '\n';
}
}
G Operating on a Graph
题意
给一个图,一开始每个点$i$,属于$i$类,每次操作会吧某个类$x$的相邻的类归为$x$,求最后每个点属于那个类
Solution
并查集模拟
list<int> lk[MAX];
vector<int> G[MAX];
int fa[MAX];
int Find(int x) {
return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
int main(){
#ifdef DEBUG
freopen64("in", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--)
{
int n, m;
scanf("%d%d",&n, &m);
for(int i = 1; i <= n; i++){
G[i].clear();
fa[i] = i;
lk[i].clear();
lk[i].push_back(i);
}
for(int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
u++, v++;
G[u].push_back(v);
G[v].push_back(u);
}
int q;
scanf("%d",&q);
while (q--)
{
int o;
scanf("%d", &o);
o++;
int siz = lk[o].size();
if(Find(o) != o) continue;
for(int i = 0; i < siz; i++) {
int cur = lk[o].front();
lk[o].pop_front();
for(int j = 0; j < G[cur].size(); j++) {
int v = G[cur][j];
int pv = Find(v);
if(pv != o) {
fa[pv] = o;
lk[o].splice(lk[o].end(), lk[pv]);
}
}
}
}
for(int i = 1; i <= n; i++)
printf("%d ", Find(i)-1);
puts("");
}
return 0;
}