A - Adjacent Product
题意:
代码:
int n, a[maxn];
void solve(){
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
for(int i = 1; i < n; i++)
cout << a[i] * a[i+1] << " \n"[i == n-1];
return;
}
B - Piano
题意:
代码:
int prew[maxn], preb[maxn];
int w, b;
void solve(){
string s = "wbwbwwbwbwbw";
for(int i = 1; i <= 20; i++)
s += s;
s = "?" + s;
for(int i = 1; i <= 200; i++){
prew[i] = prew[i-1] + (s[i] == 'w');
preb[i] = preb[i-1] + (s[i] == 'b');
}
cin >> w >> b;
auto check = [&](int l, int r){
int cntw = prew[r] - prew[l-1];
int cntb = preb[r] - preb[l-1];
return w == cntw && cntb == b;
};
int flag = 0;
for(int i = 1; i <= 12; i++){
int len = w+b;
int l = i;
int r = l+len-1;
if(check(l, r) == true){
flag = 1;
break;
}
}
if(flag)
cout << "Yes" << endl;
else
cout << "No" << endl;
return;
}
C - Σ
题意:
代码:
ll n, k, x;
ll a[maxn];
void solve(){
cin >> n >> k;
set<ll> s;
ll sum = (k+1) * k / 2;
for(int i = 1; i <= n; i++){
cin >> x;
if(x <= k){
if(s.find(x) == s.end())
sum -= x;
s.insert(x);
}
}
cout << sum << endl;
return;
}
D - Gomamayo Sequence
题意:
解析:
恰好一个位置 i i i 可以与 i + 1 i+1 i+1 处相同。
令
f
i
,
0
/
1
f_{i,0/1}
fi,0/1 为前
i
i
i 个位置相邻位置不同的最小代价,
f
i
,
0
f_{i,0}
fi,0 为不修改位置 i ,
f
i
,
1
f_{i,1}
fi,1 为修改位置
i
i
i 。
令
g
i
,
0
/
1
g_{i,0/1}
gi,0/1 为从
i
i
i 到最后相邻位置不同的最小代价。
枚举相同的位置 i i i,计算对答案的贡献。
代码:
int n;
string s;
ll f[maxn][2], g[maxn][2];
ll c[maxn];
void solve(){
cin >> n >> s;
for(int i = 1; i <= n; i++)
cin >> c[i];
s = "?" + s;
ll ans = INF;
f[1][0] = 0, f[1][1] = c[1];
for(int i = 2; i <= n; i++){
if(s[i] == s[i-1]){
f[i][0] = f[i-1][1];
f[i][1] = f[i-1][0] + c[i];
}
else{
f[i][0] = f[i-1][0];
f[i][1] = f[i-1][1] + c[i];
}
}
g[n][0] = 0, g[n][1] = c[n];
for(int i = n-1; i >= 1; i--){
if(s[i] == s[i+1]){
g[i][0] = g[i+1][1];
g[i][1] = g[i+1][0] + c[i];
}
else{
g[i][0] = g[i+1][0];
g[i][1] = g[i+1][1] + c[i];
}
}
for(int i = 1; i < n; i++){
if(s[i] == s[i+1]){
ll res = min(f[i][1] + g[i+1][1], f[i][0] + g[i+1][0]);
ans = min(ans, res);
}
else{
ll res = min(f[i][1] + g[i+1][0], f[i][0] + g[i+1][1]);
ans = min(ans, res);
}
}
cout << ans << endl;
return;
}
E - Paint
题意:
解析:
倒序遍历操作序列,维护当前所剩的行和列。
对于涂一行操作 ( 1 , a , x ) (1, a, x) (1,a,x),如果第 a 行还存在,此时列数为 b,则会有 b 个位置被涂为颜色 x,然后将第 a 行删除。涂列操作同理
代码:
#define int ll
int h, w, m;
struct oper{
int op, p, x;
oper(int op, int p, int x) : op(op), p(p), x(x){}
};
void solve(){
cin >> h >> w >> m;
vector<oper> ops;
map<int, int> res;
unordered_set<int> col, row;
for(int i = 1; i <= h; i++)
row.insert(i);
for(int i = 1; i <= w; i++)
col.insert(i);
for(int i = 1, op, p, x; i <= m; i++){
cin >> op >> p >> x;
ops.push_back(oper(op, p, x));
}
while(ops.size()){
oper op = ops.back();
ops.pop_back();
if(op.op == 1){
auto it = row.find(op.p);
if(it != row.end()){
res[op.x] += col.size();
row.erase(it);
}
}
else if(op.op == 2){
auto it = col.find(op.p);
if(it != col.end()){
res[op.x] += row.size();
col.erase(it);
}
}
if(col.size() == 0 || row.size() == 0) break;
}
if(row.size() && col.size())
res[0] += row.size() * col.size();
cout << res.size() << endl;
for(auto it = res.begin(); it != res.end(); it++){
if(it->second == 0) continue;
cout << it->first << " " << it->second << endl;
}
return;
}
F - SSttrriinngg in StringString
题意:
解析:
二分答案。
对于检查二分值 x 是否可行:因为是子序列,所以贪心的进行匹配,判断需要的串 s s s 的个数是否大于 n n n。
因为需要记录s串已经匹配的位置,以及s串里每个字符的位置。所以预处理出s串字符个数的前缀和,以及每个字符的位置。
二分的右边界为1e17。
代码:
int sum[maxn][30];
void solve(){
string s, t;
int n;
cin >> n >> s >> t;
int lens = s.length();
int lent = t.length();
s = "?" + s;
t = "?" + t;
vector<vector<int>> pos(26);
for(int i = 1; i <= lens; i++){
for(int j = 0; j < 26; j++)
sum[i][j] = sum[i-1][j];
sum[i][s[i]-'a']++;
pos[s[i]-'a'].push_back(i);
}
auto check = [&](int x){
int cnt = 0;
int p = 0;
for(int i = 1; i <= lent && cnt <= n; i++){
int ch = t[i] - 'a';
int num = sum[lens][ch];
if(num == 0) return false;
int need = x + sum[p][ch];
cnt += (need + num - 1) / num - 1;
need = need % num;
if(need == 0) p = pos[ch].back();
else p = pos[ch][need-1];
}
return cnt <= n;
};
int l = 1, r = 1e17;
int ans = 0;
while(l <= r){
int mid = (l+r) >> 1;
if(check(mid)){
l = mid+1;
ans = mid;
}
else
r = mid-1;
}
cout << ans << endl;
return;
}
G - Alone
题意:
解析:
假设 a [ i ] = x a[i] = x a[i]=x。
位置 i i i 左侧距离 i i i 最近的 a [ j ] = x a[j] = x a[j]=x,令 p r e [ i ] = j pre[i] = j pre[i]=j;位置 i i i 右侧距离 i i i 最近的 a [ j ] = x a[j] = x a[j]=x,令 s u f [ i ] = j suf[i] = j suf[i]=j。
位置 i i i 对答案的贡献为 ( i − p r e [ i ] ) × ( s u f [ i ] − i ) (i-pre[i]) \times (suf[i]-i) (i−pre[i])×(suf[i]−i),可以看成长为 ( i − p r e [ i ] ) (i-pre[i]) (i−pre[i]) ,宽为 ( s u f [ i ] − i ) (suf[i]-i) (suf[i]−i) 的矩形的面积。
在一个区间内,可能有多个数字只出现一次,所以求的是矩形面积并,而不是矩形面积和。
扫描线求矩形面积并。
代码:
struct line{
int l, r, h;
int v;
line(){}
line(int l, int r, int h, int v) : l(l), r(r), h(h), v(v){}
bool operator < (const line &b) const{
return h < b.h;
}
};
struct node{
int l, r, cnt;
ll len;
}t[maxn << 4];
vector<int> X;
int pre[maxn], suf[maxn], pos[maxn];
int n, a[maxn];
ll ans;
int ls(int k){return k << 1;}
int rs(int k){return k << 1 | 1;}
void pushup(int k){
int l = t[k].l, r = t[k].r;
if(t[k].cnt)
t[k].len = X[r+1] - X[l];
else
t[k].len = t[ls(k)].len + t[rs(k)].len;
}
void build(int k, int l, int r){
t[k].l = l, t[k].r = r;
t[k].cnt = 0;
t[k].len = 0;
if(l == r)
return;
int mid = (l+r) >> 1;
build(ls(k), l, mid);
build(rs(k), mid+1, r);
}
void modify(int k, int x, int y, int v){
if(x <= t[k].l && y >= t[k].r){
t[k].cnt += v;
pushup(k);
return;
}
int mid = (t[k].l + t[k].r) >> 1;
if(x <= mid)
modify(ls(k), x, y, v);
if(y > mid)
modify(rs(k), x, y, v);
pushup(k);
}
void solve(){
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
for(int i = 1; i <= n; i++){
pre[i] = pos[a[i]];
pos[a[i]] = i;
}
for(int i = 1; i <= n; i++)
pos[i] = n+1;
for(int i = n; i >= 1; i--){
suf[i] = pos[a[i]];
pos[a[i]] = i;
}
vector<line> lines;
X.push_back(-1);
for(int i = 1; i <= n; i++){
int x1 = pre[i]+1, x2 = i+1, y1 = i, y2 = suf[i];
lines.push_back(line(x1, x2, y1, 1));
lines.push_back(line(x1, x2, y2, -1));
X.push_back(x1);
X.push_back(x2);
}
sort(X.begin(), X.end());
X.erase(unique(X.begin(), X.end()), X.end());
int m = X.size();
build(1, 1, m-2);
sort(lines.begin(), lines.end());
for(int i = 0; i < lines.size()-1; i++){
int l = lower_bound(X.begin(), X.end(), lines[i].l) - X.begin();
int r = lower_bound(X.begin(), X.end(), lines[i].r) - X.begin();
modify(1, l, r-1, lines[i].v);
ans += t[1].len * (lines[i+1].h - lines[i].h);
}
cout << ans << endl;
return;
}