CF R866 div.2
A
当一个"_ "的右边没有“^”时,答案增加,发现这对于中间的序列是充分必要的。
当位置 \(1\) 为 "_"时,我们必须在其前面加一个"^";当整个字符串为 "^"时,特判一下答案。
B
发现给定01串当全是“1”时,我们直接输出 \(n*n\)。考虑一般的情况,我们发现将面积表示出来
\(S=a+b,a+b=x\),\(x\)为定值,即连续的“1”的最大个数。那么我们就由均值不等式可知当 \(a=b\)时,面积最大。
考虑实际,当 \(x=2*k+1\),即为奇数时,不能使 \(a=b\),那么我们让 \(a=b-1\),此时面积最大。
由于题目的性质,我们需要将首尾连成圈来确定这个 \(x\) 的值。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
int T, n;
char s[N << 1];
int main(){
cin >> T;
while(T --){
cin >> (s + 1);
n = strlen(s + 1);
bool flag = true;
LL ans = 0;
int maxn = 0, cnt = 0;
for(int i = 1; i <= n; i++)
if(s[i] == '0')
flag = false, maxn = max(maxn, cnt), cnt = 0;
else cnt ++;
for(int i = 1; i <= n; i++)
if(s[i] == '0')
flag = false, maxn = max(maxn, cnt), cnt = 0;
else cnt ++;
maxn = max(cnt, maxn);
if(flag) ans = (LL)n * n;
else {
if(maxn % 2 == 0) ans = (LL)maxn / 2 * (LL)(maxn / 2 + 1);
else ans = (LL) (maxn + 1) / 2 * (maxn + 1) / 2;
}
cout << ans << endl;
}
return 0;
}
C
首先,我们考虑这样一个问题:若使得这个改变后的序列的 \(mex\) 值比原来大 \(1\) ,需要满足什么条件。
我们进行一次操作后,设原来的 \(mex\) 值为 \(M\) 不难发现:
- 1 要让新序列有 \(1 \sim M\) 的至少一个元素。
- 2 要使新序列中不含有 \(M+1\) 的元素,否则新的 \(mex\) 值不可能为 \(M+1\)。
那么我们同时明确了这次操作的目的,我们采取这样的方式来模拟操作。
由于第二点的必要性且我们只有一次操作,我们将序列中的所有 \(M+1\) 给赋值为 \(M\) ,若新序列不符合要求,那一定无解。
对于剩下的情况,我们还需要特判一下该序列是不是一个 \(1 \sim M-1\) 的排列(这也是不合法的)。
其他情况均合法,且此方案可行。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int T, n, a[N], A[N];
int main(){
cin >> T;
while(T --){
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]), A[i] = a[i];
sort(A + 1, A + n + 1);
int cnt = 0;
bool flag = true;
for(int i = 1; i <= n; i++)
if(A[i] == cnt) cnt ++;
else flag = false;
if(flag){
puts("NO");
continue;
}
int l = 0, r = n + 1;
for(int i = 1; i <= n; i++)
if(a[i] == cnt + 1){
l = i;
break;
}
for(int i = n; i; i--)
if(a[i] == cnt + 1){
r = i;
break;
}
for(int i = l; i <= r; i++)
a[i] = cnt;
sort(a + 1, a + n + 1);
int cntt = 0;
for(int i = 1; i <= n; i++)
if(a[i] == cntt) cntt ++;
if(cnt == cntt - 1 || l == 0) puts("YES");
else puts("NO");
}
return 0;
}
D
由于本题性质,所以我们可以找到最大的长和宽 \(Mn,Mm\)。
并且,原矩形至多只有两种情况:(\(Mn\),\(S/Mn\)),(\(S/Mm\),\(Mm\)),\(S\)面积可以通过输入直接计算。
现在我们需判断这两种情况的合法性,我们发现可以暴力模拟判断。
用 \(map\) 存给定子矩形,每次可以通过 \(map\) 判断,在 \(O(nlogb)\) 的时间内完成
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int T, n;
int main(){
cin >> T;
while(T --){
cin >> n;
map<LL, multiset<LL>> mp1, mp2;
LL maxw = 0, maxh = 0;
LL S = 0;
for(int i = 1; i <= n; i++){
LL a, b;
scanf("%lld%lld", &a, &b);
mp1[a].insert(b);
mp2[b].insert(a);
maxw = max(maxw, a);
maxh = max(maxh, b);
S += (LL)a * b;
}
set<pair<LL, LL>> ans;
auto check = [](int n, LL W, LL H, int idx, map<LL, multiset<LL>> mp1, map<LL, multiset<LL>> mp2){
while(W > 0 && H > 0){
LL tot = 0;
if(idx == 0){
for(auto it: mp1[W]){
tot += it;
n --;
mp2[it].erase(mp2[it].find(W));
}
H -= tot;
idx = 1 - idx;
}
else{
for(auto it: mp2[H]){
tot += it;
n--;
mp1[it].erase(mp1[it].find(H));
}
W -= tot;
idx = 1 - idx;
}
if(tot == 0) return false;
}
if(n != 0) return false;
return true;
};
if(S % maxw == 0 && check(n, maxw, S / maxw, 0, mp1, mp2))
ans.insert({maxw, S / maxw});
if(S % maxh == 0 && check(n, S / maxh, maxh, 1, mp1, mp2))
ans.insert({S / maxh, maxh});
cout << ans.size() << '\n';
for(auto t : ans)
cout << t.first << ' ' << t.second << endl;
}
return 0;
}