容易发现多个数和 1 1 1个数的操作次数为求和关系。于是考虑一个数的情况,显然与 x − 1 x - 1 x−1操作次数的奇偶性有关。那么对所有数统计操作次数判断奇偶性即可。
#include
#define int long long
using namespace std;
inline void solve(){
int n; cin >> n;
int cnt = 0;
for(int i = 1; i <= n; i++){
int num ; cin >> num;
cnt += num - 1;
}
if(cnt & 1) cout << "errorgorn\n";
else cout<<"maomao90\n";
}
signed main(){
int t = 0; cin >> t;
while(t--) solve();
return 0;
}
分类讨论题:
#include
#define int long long
using namespace std;
inline void solve(){
string s; cin >> s;
int cnt1 = 0, cnt2 = 0;
if(s.size() == 1 || s.back() != 'B' || s[0] == 'B'){
cout << "NO\n";
return;
}
for(auto ch : s){
if(ch == 'A') cnt1++; else cnt2++;
if(cnt1 - cnt2 < 0){
cout << "NO\n";
return;
}
}
cout << "YES\n";
}
signed main(){
int t = 0; cin >> t;
while(t--) solve();
return 0;
}
可以发现一个性质,如果要保证equality
小于等于 1 1 1,操作的下标序列一定连续,否则至少产生两组相同的数。
那么我们直接从左右端点向中间找到需要修改的最短区间即可。
#include
#define int long long
using namespace std;
const int N = 2e5 + 10;
int a[N];
inline void solve(){
int n = 0; cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
int l = 1, r = n;
while(l < n && a[l] != a[l + 1]) l++; l++;
while(r > 1 && a[r] != a[r - 1]) r--; r--;
if(l > r) cout << "0\n";
else cout << max(r - l, 1ll) << '\n';
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
int t = 0; cin >> t;
while(t--) solve();
return 0;
}
首先处理出 A A A中每个数字下一次出现的位置,然后两个指针从头开始匹配,当碰到不相等的时候对端点数字打标记,并倾斜对齐继续匹配,直至碰到与之前端点相同的数字,那么该段序列可以通过循环左移得到。如果碰到一个上下不匹配,而上方元素无后继的情况一定非法。
#include
#define int long long
using namespace std;
const int N = 2e5 + 10, INF = 1e9;
int a[N], b[N], last[N], nxt[N];
map<int, int> mp;
inline void solve(){
mp.clear();
int n = 0; cin >> n;
memset(last, 0, sizeof(int) * (n + 10));
memset(nxt, 0, sizeof(int) * (n + 10));
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) cin >> b[i];
for(int i = n; i; i--){
if(last[a[i]]) nxt[i] = last[a[i]];
last[a[i]] = i;
}
bool flag = true;
for(int l = 1, r = 1;;){
if(r > n) break;
else if(a[l] != b[r]){
if(nxt[l]) mp[a[l]]++, l++;
else{
flag = false;
break;
}
} else if(a[l] == b[r]){
if(mp.count(b[r]) && mp[b[r]]) mp[b[r]]--;
else l++;
r++;
}
}
if(!flag) cout << "NO\n";
else cout << "YES\n";
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
int t = 0; cin >> t;
while(t--)
solve();
return 0;
}
首先,我们可以二分询问,得到所有单词在一行显示的宽度 W W W,最多需要 30 30 30次可得。然后我们枚举两行、三行 … n \dots n …n行显示单词的高度 h h h,取面积 m i n min min即可。注意如果回答 h = 0 h = 0 h=0时代表放不下最长单词,此时直接break
掉即可。
#include
#define int long long
using namespace std;
const int N = 2e5 + 10, INF = 1e9;
int a[N];
int ask(int ans){
cout << "? " << ans << endl;
cin >> ans;
return ans;
}
inline void solve(){
int n = 0; cin >> n;
int l = 1, r = INF, ans = 0;
while(l <= r){
int mid = l + r >> 1;
if(ask(mid) == 1) r = mid - 1;
else l = mid + 1;
}
ans = l;
for(int i = 2; i <= n; i++){
int tmp = ask(l / i);
if(!tmp) break;
else ans = min(ans, (l / i) * tmp);
}
cout << "! " << ans << endl;
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
//int t = 0; cin >> t;
//while(t--)
solve();
return 0;
}
要求每次选择两个数列元素交换,使原始序列 A A A变为目标序列 B B B。现在给定 A A A,构造一个 B B B,使操作次数最大。
首先我们对于原始序列和目标序列,对每个元素从最终位置 i i i向初始位置 j j j建边。例如:
A = [1,2,3,1,2,3]
B = [3,1,2,2,3,1]
以上为例,我们可以取每个数字的交换后的最近位置建图如下:
这样的环将原序列分成了若干段,每段可以独立交换,每段交换的操作数=环的长度 − 1 -1 −1。
当然我们可以取交换后相对更远的位置(也就是更大的环),但是这样的情况一定更劣,因为在环总长度固定的前提下,大环 − 1 -1 −1的更少。
那么我们的策略就很明显了,将给定的 A A A分隔成若干个尽可能大而没有重复元素的子序列,对于每个环循环移位一次即可。
#include
#define endl '\n'
using namespace std;
const int N = 3e6 + 10;
int a[N], b[N];
inline void solve(){
int n = 0, cnt = 0; cin >> n;
unordered_map<int, queue<int>> g;
for(int i = 1; i <= n; i++) cin >> a[i], g[a[i]].emplace(i);
while(cnt < n){
vector<int> pos;
for(auto it = g.begin(); it != g.end(); ){
if((it -> second).size() == 0){
auto del = it++;
g.erase(del);
continue;
}
if((it -> second).size()){
pos.emplace_back((it -> second).front());
(it -> second).pop();
cnt++, it++;
}
}
for(int i = 0; i < pos.size(); i++){
b[pos[i]] = a[pos[(i + 1) % pos.size()]];
}
}
for(int i = 1; i <= n; i++) cout << b[i] << " \n"[i == n];
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
int t = 0; cin >> t;
while(t--) solve();
return 0;
}
大受震撼
没看懂,待补。
#include
#define endl '\n'
using namespace std;
const int N = 3e6 + 10;
char s[N];
int sum0[N], sum1[N];
inline void solve(){
int n = 0, m = 0; cin >> n >> m >> s + 1;
for(int i = 1;s[i];++i) {
sum0[i] = sum0[i - 1] + (s[i] == '0' && s[i] == s[i - 1]);
sum1[i] = sum1[i - 1] + (s[i] == '1' && s[i] == s[i - 1]);
}
while(m--) {
int l, r; cin >> l >> r;
cout << max(sum0[r] - sum0[l], sum1[r] - sum1[l]) + 1 << endl;
}
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
solve();
return 0;
}