Divide by Zero 2021 and Codeforces Round #714 (Div. 2)
A - Array and Peaks
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m; set<int> st;
if ((n - 1) / 2 < m) { cout << "-1
"; continue; }
rep (i, 2, n) st.insert(i); cout << 1 << ' ';
while (m) {
auto it = st.begin(); ++it;
cout << *it << ' ' << *st.begin() << ' ';
st.erase(st.begin()); st.erase(st.begin()); --m;
}
for (auto &i : st) cout << i << ' '; cout << '
';
}
return 0;
}
B - AND Sequences
由题意得(x & z = y, x = z & y)
则(x >= x & z = y, y >= z & y = x) 即 (x = y 且 x & z = y & z = x = y)
int a[30];
ll s[N];
int main() {
IOS; s[0] = 1;
rep (i, 1, 2e5) s[i] = s[i - 1] * i % mod;
for (cin >> _; _; --_) {
cin >> n; map<int, ll> st; memset(a, 0, sizeof a);
rep (i, 1, n) {
cin >> m, ++st[m];
rep (j, 0, 29) if (m >> j & 1) ++a[j];
}
ll ans = 0;
for (auto &p : st) {
bool f = 1;
rep (j, 0, 29) if ((p.fi >> j & 1) && a[j] != n) f = 0;
if (f) ans = (ans + p.se * (p.se - 1) % mod) % mod;
}
cout << ans * s[n - 2] % mod << '
';
}
return 0;
}
C - Add One
dp (f(i, j)) 表示从0开始经过(i)次增加, 数字(j)有几个
int f[N][10];
int main() {
IOS; f[0][0] = 1;
rep (i, 1, 2e5 + 10) {
f[i][0] = f[i - 1][9], f[i][1] = (f[i - 1][9] + f[i - 1][0]) % mod;
rep (j, 2, 9) f[i][j] = f[i - 1][j - 1];
}
for (cin >> _; _; --_) {
cin >> n >> m; int ans = 0;
for (; n; n /= 10) rep (i, 0, 9) ans = (ans + f[m + n % 10][i]) % mod;
cout << ans << '
';
}
return 0;
}
D - GCD and MST
注意到(gcd(a([l, r])) = a[i])则必有(min(a([l, r]))=a[i]), 枚举区间就行了
int a[N];
PII b[N];
bool v[N];
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m; ll ans = 0; k = n - 1;
rep (i, 1, n) cin >> a[i], b[i] = { a[i], i }, v[i] = 0; sort(b + 1, b + 1 + n);
rep (i, 1, n) if (!v[b[i].se]) {
if (b[i].fi >= m) break;
int l = b[i].se, r = b[i].se;
while (l > 1 && !v[l] && a[l - 1] % b[i].fi == 0) --l;
while (r < n && !v[r] && a[r + 1] % b[i].fi == 0) ++r;
k -= r - l; rep (j, l, r) v[j] = 1; ans += (ll)(r - l) * b[i].fi;
}
ans += (ll)k * m; cout << ans << '
';
}
return 0;
}
E - Cost Equilibrium
先判断是否存在
然后当要增大(减小)的数 == 1时, 直接去重全排列,
否则要增大的数,要减小的数, 必定各自为营, 不存在相互交叉
否则最大最小价值不一样
当两者无交叉的时候, 要增大的数内之际无论怎么操作, 最后都等价于要减小的数让其变大(相当于均摊纸牌)
注意相同的数去重就行
const int N = 1e5 + 5, mod = 1e9 + 7;
int n, m, _, k, cas;
ll fac[N], facinv[N], inv[N];
int a[N];
void init(int n) {
fac[0] = fac[1] = facinv[0] = facinv[1] = inv[0] = inv[1] = 1;
rep(i, 2, n)
fac[i] = fac[i - 1] * i % mod,
inv[i] = inv[mod % i] * (mod - mod / i) % mod,
facinv[i] = facinv[i - 1] * inv[i] % mod;
}
int main() {
IOS; cin >> n; init(n); ll s = 0;
rep(i, 1, n) cin >> a[i], s += a[i];
if (s % n) return cout << 0, 0;
sort(a + 1, a + 1 + n); s /= n;
int l = lower_bound(a + 1, a + 1 + n, s) - a, r = upper_bound(a + 1, a + 1 + n, s) - a - 1;
if (l == 1 && r == n) return cout << 1, 0;
ll x = fac[l - 1], y = fac[n - r], ans = fac[n] * facinv[r - l + 1] % mod * facinv[n - r + l - 1] % mod;
for (int i = 1, c = 0; i < l; ++i, ++c) if (a[i] != a[i + 1]) x = x * facinv[++c] % mod, c = -1;
for (int i = n, c = 0; i > r; --i, ++c) if (a[i] != a[i - 1]) y = y * facinv[++c] % mod, c = -1;
if (l == 2) cout << ans * y % mod * (n - r + l - 1) % mod;
else if (r == n - 1) cout << ans * x % mod * l % mod;
else cout << ans * x % mod * y % mod * 2 % mod;
return 0;
}