A
奇数和偶数分别相邻即可
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cctype>
#include <cmath>
#include <cstring>
#include <stack>
#include <tuple>
#include <numeric>
#include <map>
#include <set>
#define forn(i, n) for(int i = 0; i < int(n); ++i)
#define debug(i) cout << "<< " << i << " >>" << endl;
#define pi acos(-1)
using namespace std;
using ll = long long;
template <typename T> void read(T & x){
x = 0; int op = 1; char ch = getchar();
while (!isdigit(ch)){ if (ch == '-') op = -1; ch = getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48); ch = getchar();}
x*= op;
}
void solve(){
int n;
read(n);
vector<int> odd;
vector<int> even;
for (int i = 0, x; i < n; ++i) {
read(x);
if (x & 1){
odd.push_back(x);
}else{
even.push_back(x);
}
}
for (int e : odd) {
cout << e << " ";
}
for (int e : even){
cout << e << " ";
}
cout << '\n';
}
signed main(){
int t;
read(t);
while (t--){
solve();
}
}
B
维护前缀和,正着倒着各扫一遍,确保每个扫到的M,前面(后面)T的数量要大于M的数量
const int N = 1e5 + 100;
int sum[N];
char s[N];
int get(int l, int r){
return sum[r] - sum[l - 1];
}
void solve() {
int n;
read(n);
memset(sum, 0, sizeof sum);
scanf("%s", s + 1);
int t = 0, m = 0;
for (int i = 1; i <= n; ++i) {
if (s[i] == 'T') {
t++;
sum[i] = 1;
} else {
m++;
}
}
for (int i = 1; i <= n; ++i) {
sum[i] += sum[i - 1];
}
if (t != 2*m){
cout << "NO" << endl;
return;
}
int flag = 1;
m = 0;
for (int i = 1; i <= n; ++i) {
if (s[i] == 'M'){
m++;
if (get(1, i) < m){
flag = 0;
break;
}
}
}
m = 0;
for (int i = n; i >= 1; --i) {
if (s[i] == 'M'){
m++;
if (get(i, n) < m){
flag = 0;
break;
}
}
}
if (flag){
cout << "YES" << endl;
}else{
cout << "NO" << endl;
}
}
signed main(){
int t;
read(t);
while (t--){
solve();
}
}
C
排序后区间动态规划,注意开long long
#define int long long
void solve() {
read(n);
for (int i = 1; i <= n; ++i) {
read(a[i]);
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
dp[i][j] = 1e12;
}
}
for (int i = 0; i <= n; ++i) {
dp[i][i] = 0;
}
for (int len = 2; len <= n; ++len) {
for (int i = 1; i <= n - len + 1; ++i) {
int j = i + len - 1;
dp[i][j] = min(dp[i][j], dp[i][j - 1] + a[j] - a[i]);
dp[i][j] = min(dp[i][j], dp[i + 1][j] + a[j] - a[i]);
}
}
cout << dp[1][n] << endl;
}
signed main(){
int t = 1;
//read(t);
while (t--){
solve();
}
}
D
三指针?p0, p1, p2至少有一对相等,更新到最后的指向分别是n, t, s
那么res的长度为(2n + s + t)/ 2
于是加上剩下的一段,容易证明
(2n + s + t)/ 2 + (2n - max(s, t)) <= 3*n
于是可构造结果
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <vector>
using namespace std;
using ll = long long;
template <typename T> void read(T & x){
x = 0; int op = 1; char ch = getchar();
while (!isdigit(ch)){ if (ch == '-') op = -1; ch = getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48); ch = getchar();}
x*= op;
}
void solve(){
string s[3];
int n;
read(n);
for (int i = 0; i < 3; ++i) {
cin >> s[i];
}
string res;
int p[3] = {0, 0, 0};
while (*max_element(p, p + 3) != 2*n){
if (s[0][p[0]] == s[1][p[1]]){
res.push_back(s[0][p[0]]);
p[0]++;
p[1]++;
}else if (s[0][p[0]] == s[2][p[2]]){
res.push_back(s[0][p[0]]);
p[0]++;
p[2]++;
}else if (s[1][p[1]] == s[2][p[2]]){
res.push_back(s[1][p[1]]);
p[1]++;
p[2]++;
}
}
vector<int> num(p, p + 3);
sort(num.begin(), num.end());
int pos = num[1];
int id = -1;
for (int i = 0; i < 3; ++i) {
if (p[i] == pos) id = i;
}
for (int i = pos; i < 2*n; ++i) {
res.push_back(s[id][i]);
}
cout << res << '\n';
}
signed main(){
int cases;
read(cases);
while (cases--){
solve();
}
}
E
对于almost sorted 长度为n的序列,按字典顺序从小到大,有
1, …
2, 1…
3, 2, 1…
n, n - 1, n -2, … 1
不难得出一下的递推公式
(a[n]为方案总数
对于1, …, 后面的2 ~ n 可看作1 ~ n - 1的almost sorted排列整体加一)
/*
*
* a[n] = a[n - 1] + a[n - 2] + ... + a[1] + a[0]
* a[n] = 2^(n-1)
* a[0] = 1
*/
递归求解即可, 不过要注意n的范围1e5,直接算2^n行不通,需要一些特殊的处理,详见代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <vector>
using namespace std;
using ll = long long;
template <typename T> void read(T & x){
x = 0; int op = 1; char ch = getchar();
while (!isdigit(ch)){ if (ch == '-') op = -1; ch = getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48); ch = getchar();}
x*= op;
}
/*
* a[n] = a[n - 1] + a[n - 2] + ... + a[1]
* a[n] = 2^n-1
*
*/
int get(vector<int> &res, int delta, ll n, ll k){
if (k == 0 || n == 0){
return 1;
}
ll tot = 1;
for (ll i = 1; i <= n - 2; ++i) {
tot *= 2;
if (tot >= k){
break;
}
}
if (tot > k){
res.push_back(1 + delta);
get(res, delta + 1, n - 1, k);
return 1;
}
int cnt = 1;
while (k > tot && tot){
k -= tot;
tot /= 2;
cnt++;
}
for (int i = cnt; i >= 1; --i) {
res.push_back(i + delta);
}
get(res, delta + cnt, n - cnt, k);
return 1;
}
void solve(){
ll n, k;
read(n), read(k);
ll tot = 1;
for (int i = 0; i < n - 1; ++i) {
tot *= 2;
if (tot >= k){
break;
}
}
if (k > tot){
printf("-1\n");
return;
}
vector<int> res;
if (get(res, 0, n, k)){
for (int i : res) printf("%d ", i);
}
printf("\n");
}
signed main(){
int cases;
read(cases);
while (cases--){
solve();
}
}