F. Inversion Composition
题意:给你一个排列p,要你构造一个排列q,满足inv(q) + inv(qp)= k,inv值排列的逆序对数,qp相当于一个新的排列w,满足w(i)=q(p(i))
设pos(i)是p排列中i的位置,有p(pos(i))=i,将i 替换,式子变为w(pos(i))=q(i)
设1<=i<j<=n,从一对序列的值来看有四种可能
1. qi < qj 且 posi < posj ,则w(pos(i)) = qi < qj = w(pos(j)),都为顺序,贡献为0
2. qi < qj 且 posi > posj ,则w(pos(i)) = qi < qj = w(pos(j)),w为逆序,q为顺序,贡献为1
3. qi > qj 且 posi > posj ,则w(pos(i)) = qi > qj = w(pos(j)),w为顺序,q为逆序,贡献为1
4. qi > qj 且 posi < posj ,则w(pos(i)) = qi < qj = w(pos(j)),都为逆序,贡献为2
按第四种可能来构造w序列(那么条件变为逆序)
2*inv(w) + inv(p)= k
inv(w)= (k - inv(p)(顺序) ))/ 2
c = k - inv(p)
c为负数,基数,且过大时都是不可能构造出来的
通过树状数组可以求出逆序和顺序前缀和,我们只需要找到在顺序数组中最大的下标v即可,
将长度为v的序列按从小到大移到v+1前面,构成顺序,c -= g[ v ]
如果c有剩余,那么从p中的顺序数中找出还要多少个顺序数pos,将n,v+1,v,v-pos+2移到最前面,再将v -1,v - 2,2 ,1移入,最后移入v,即可构造
(推荐文章:树状数组求逆序对)
// Problem: F. Inversion Composition
// Contest: Codeforces - Codeforces Global Round 25
// URL: https://codeforces.com/contest/1951/problem/F
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define MAXN 300005
int p[MAXN], tr[MAXN], f[MAXN], g[MAXN], w[MAXN], q[MAXN];
inline void add(int x, int k) {
for (; x <= MAXN; x += x & -x) tr[x] += k;
}
inline int sum(int x) {
int ret = 0;
for (; x; x -= x & -x) ret += tr[x];
return ret;
}
void solve() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> p[i];
for (int i = 1; i <= n; i++) {
f[i] = i - 1 - sum(p[i]), g[i] = sum(p[i] - 1);
add(p[i], 1);
}
for (int i = 1; i <= n; i++) {
add(p[i], -1);
}
for (int i = 1; i <= n; i++) {
f[i] += f[i - 1], g[i] += g[i - 1];
}
k -= f[n];
if (k < 0 || k % 2 || k > (n * (n - 1) - 2 * f[n])) {
cout << "NO" << endl;
return;
}
k /= 2;
int v = n;
v = lower_bound(g + 1, g + 1 + n, k) - g - 1;
int x = k - g[v];
int cnt = 0, pos = 0;
while (cnt < x) {
cnt += (p[++pos] < p[v + 1]);
}
x = pos;
for (int i = 1; i <= x; i++) {
w[i] = v - i + 2;
}
for (int i = x + 1; i <= v; i++) {
w[i] = v - i + 1;
}
w[v + 1] = v - x + 1;
for (int i = v + 2; i <= n; i++) w[i] = i;
for (int i = 1; i <= n; i++) {
q[p[i]] = w[i];
}
cout << "YES" << endl;
for (int i = 1; i <= n; i++) cout << q[i] << " ";
cout << endl;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
std::cin >> t;
while (t--) solve();
return 0;
}
E. No Palindromes
题意:给你一个字符串,将字符串切割为几个子串,满足每个子串都是非回文串
假如一个字符串本身不是回文串,那么即使答案
是回文串的话,我们枚举每一位,看看能不能拆成两个非回文串
用哈西表来判断字符串是否为回文串
(推荐文章:哈西判断回文串)
// Problem: E. No Palindromes
// Contest: Codeforces - Codeforces Global Round 25
// URL: https://codeforces.com/contest/1951/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// ped by CP Editor (https://cpeditor.org)
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define ULL unsigned long long
using namespace std;
const int N = 1e6 + 5, P = 23;
char s[N], q[N];
ULL h1[N], h2[N], p1[N], p2[N], n;
void init1() {
p1[0] = 1;
for (int i = 1; i <= n; i++) {
h1[i] = h1[i - 1] * P + s[i];
p1[i] = p1[i - 1] * P;
}
}
void init2() {
p2[0] = 1;
for (int i = 1; i <= n; i++) {
h2[i] = h2[i - 1] * P + q[i];
p2[i] = p2[i - 1] * P;
}
}
ULL get1(int l, int r) { return h1[r] - h1[l - 1] * p1[r - l + 1]; }
ULL get2(int l, int r) { return h2[r] - h2[l - 1] * p2[r - l + 1]; }
void solve() {
cin >> (s + 1);
n = strlen(s + 1);
for (int i = 1; i <= n; i++) {
q[i] = s[n - i + 1];
}
init1();
init2();
if (get1(1, n) != get2(1, n)) {
cout << "YES\n1\n";
cout << s + 1 << endl;
return;
}
for (int i = 2; i < n - 1; i++) {
if (get1(1ll, i) != get2(n - i + 1, n) &&
get2(i + 1, n) != get2(1ll, n - i)) {
cout << "YES\n2\n";
for (int j = 1; j <= i; j++) cout << s[j];
cout << " ";
for (int j = i + 1; j <= n; j++) cout << s[j];
cout << endl;
return;
}
}
cout << "NO" << endl;
}
signed main() {
// ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
std::cin >> t;
while (t--) solve();
return 0;
}
D. Buying Jewels
题意:构造一个物品序列,满足用a金钱恰好买b个物品,对于每物品,买到金钱不足为止
如果a能被b整除,结果就是a/b,或者构造b-1和1 a满足只能买一个b-1即可,否则没有答案
// Problem: D. Buying Jewels
// Contest: Codeforces - Codeforces Global Round 25
// URL: https://codeforces.com/contest/1951/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int N = 2e5;
void solve() {
int a, b;
cin >> a >> b;
if (a % b == 0) {
cout << "YES" << endl;
cout << 1 << endl;
cout << a / b << endl;
} else {
if ((a + 1) / 2 >= b) {
cout << "YES" << endl;
cout << 2 << endl;
cout << a - b + 1<< " " << 1 << endl;
} else {
cout << "NO" << endl;
}
}
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
std::cin >> t;
while (t--) solve();
return 0;
}