每日一训(3)

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;
}

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值