Codeforces Round #672 (Div. 2)
C2. Pokémon Army (hard version)
题意:给你一个a数组让你找到一个子数组b求 b[1] - b[2] + b[3] - b[4]……的最大值并且有q次询问每次询问一个l和r表示将a数组的a[l],与a[r]交换, 每次询问都让你求一次最大值。
题解:
如果你c1是用dp写的话, 这题就不好写了。
可以想一下每次从a选一个子数组要求答案最大的话, 其值就是查分数组的大于的0和。
如果知道了这个那么每次询问只要维护 4个值就行了。在更新答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 7;
ll n, a[N], x[N];
void solve() {
int q;
cin >> n >> q;
for (int i = 0; i <= n + 1; i++) {
x[i] = 0;
}
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
a[n + 1] = 0;
ll ans = 0;
for (int i = 1; i <= n; i++) {
x[i] = a[i] - a[i + 1];
if (x[i] > 0) ans += x[i];
}
cout << ans << endl;
while (q--) {
int l, r; cin >> l >> r;
swap(a[l], a[r]);
if (l == r) {
cout << ans << endl;
continue;
}
if (x[l] > 0) ans -= x[l];
if (x[r] > 0) ans -= x[r];
if (x[l - 1] > 0) ans -= x[l - 1];
if (x[r - 1] > 0 && r - 1 != l) ans -= x[r - 1];
x[l - 1] = a[l - 1] - a[l];
x[l] = a[l] - a[l + 1];
x[r] = a[r] - a[r + 1];
x[r - 1] = a[r - 1] - a[r];
if (x[l] > 0) {
ans += x[l];
}
if (x[r] > 0) {
ans += x[r];
}
if (l - 1 && x[l - 1] > 0) {
ans += x[l - 1];
}
if (r - 1 && l != r - 1&& x[r - 1] > 0) {
ans += x[r - 1];
}
cout << ans << endl;
}
}
int main() {
ios::sync_with_stdio(0);
int t; cin >> t;
while (t--) {
solve();
}
}
D. Rescue Nibel!
题意:
给你n盏灯, 每盏灯都会在固定时间打开, 问选k盏灯且这k盏灯在某一个时刻一定全部打开,有多少种选择方法?
题解:
这题比赛的时候没有想出来。。。太菜了。
如果枚举每个时刻有多少盏灯打开, 那在这个时刻的答案是 $$inom{k}{同时打开的灯} $$
但是会有重复计算。
所以我们可以每次只计算与开始打开灯贡献其它就不用在算了。
设(x[i])表示第 (i)个时刻有 (x[i]) 个灯打开。
设 (vis[i]) 表示 第(i)个时刻刚打开 (vis[i])个灯。
那么第(i) 个时刻的答案就是 (inom{k}{x[i]} - inom{k}{x[i] - vis[i]})
这样计算就会有重复的啦。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 7e5 + 7;
const ll mod = 998244353;
long long fac[N]; // 阶乘表
ll n, k;
vector<ll> g;
vector<pair<ll, ll> > cnt;
int get_id(ll x) {
return lower_bound(g.begin(), g.end(), x) - g.begin() + 1;
}
long long qpow(long long x, long long n) {
long long res = 1;
for (; n; n >>= 1, x = x * x % mod)
if (n & 1) res = res * x % mod;
return res;
}
long long inv(long long a) { // 返回逆元 费马小定理
return qpow(a, mod-2)%mod;
}
void solves() { // 计算阶乘表
fac[0] = 1;
for(int i = 1;i < N; i++) {
fac[i] = (fac[i-1]*i)%mod;
}
}
long long comb(long long n, long long k) {
if(k > n) return 0;
return (fac[n]*inv(fac[k])%mod * inv(fac[n-k])%mod) % mod;
}
ll x[N], vis[N];
void solve() {
solves();
cin >> n >> k;
for (int i = 1; i <= n; i++) {
ll l, r; cin >> l >> r;
g.push_back(l), g.push_back(r);
cnt.push_back({l, r});
}
sort(g.begin(), g.end());
g.erase(unique(g.begin(), g.end()), g.end());
for (int i = 0; i < cnt.size(); i++) {
int l = get_id(cnt[i].first), r = get_id(cnt[i].second);
x[l]++, x[r + 1]--;
vis[l]++;
}
for (int i = 1; i <= g.size() + 10; i++) {
x[i] += x[i - 1];
}
ll ans = 0;
for (int i = 1; i <= g.size() + 10; i++) {
if (vis[i]) {
ans = (ans + comb(x[i], k)) % mod;
ans = (ans - comb((x[i] - vis[i]), k) + mod) % mod;
}
}
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(0);
int t = 1; //cin >> t;
while (t--) {
solve();
}
}