补题:牛客练习赛57

比赛入口

还有两题太难理解…没看懂…
划分树是树形dp,但没看懂是咋dp的
最后函数求和貌似要用FFT,还没学…被自己菜哭

B 打 boss

做法:写这题时候脑子很乱(模拟杀我),最后写出来还是有因为考虑不周出现的小bug。

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define pii pair<int, int>
using namespace std;
typedef long long LL;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
int main() {
  int t; read(t);
  LL hp1, hp2, atk1, atk2, m;
  while(t--) {
    read(hp1); read(hp2); read(atk1); read(atk2); read(m);
    if(hp2 <= atk1) puts("Yes");
    else if(m >= atk1) puts("No");
    else {
      //这里是关键,(hp2 - atk1) % (atk1 - m) 就能判断出怪物最后一轮是否能撑过玩家的攻击
      LL cnt = (hp2 - atk1) / (atk1 - m) + ((hp2 - atk1) % (atk1 - m) != 0);
      if(cnt * atk2 >= hp1) puts("No");
      else puts("Yes");
    }
  }
  return 0;
}


C 装货物

做法:具体的做法大概就是爆搜,要将vis数组利用好。

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 30;
//a数组代表了第i个货物的重量,vis数组表示了第i个箱子放了多少的货物
LL n, x, W, a[N], vis[N];
int f;
bool cmp(int a1, int a2) {
  return a1 > a2;
}
void dfs(int step, int num) {
  if(f) return;
  //如果箱子数目大于了x
  if(num > x) return ;
  //如果所有货物放完了
  if(step == n + 1) {
    f = 1; return;
  }
  for(int i = 1; i <= num; ++i) {
    //如果当前箱子可以放
    if(a[step] + vis[i] <= W) {
      vis[i] += a[step];
      dfs(step+1, num);
      vis[i] -= a[step];
    }
  }
  //如果当前箱子放不下了
  vis[num+1] = a[step];
  dfs(step+1, num+1);
  vis[num+1] = 0;
}
int main() {
  int t; read(t);
  while(t--) {
    read(n); read(x); read(W);
    for(int i = 1; i <= n; ++i) read(a[i]);
    //排序为了优化搜索的复杂度
    sort(a+1, a+n+1, cmp);
    if(a[1] > W) puts("No");
    else if(n <= x) puts("Yes");
    else {
      f = 0;
      dfs(1, 1);
      if(f) puts("Yes");
      else puts("No");
    }
  }
  return 0;
}

D 回文串

做法:当时想着怎么用马拉车记录下来最长的回文串,删掉以后再看第二长的,但这样会有很多特殊情况要考虑。所以其实最优的做法就是记录出每个位置的最长回文串前缀和最长回文串后缀,最后再枚举每个点看前缀加上后缀的最大值,就是答案。(还是对马拉车不太熟悉,得好好整整dp了)

代码

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define pii pair<int, int>
using namespace std;
typedef long long LL;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 6e5+5;
/*
Len[i]表示了以i为中心的最长回文半径
如果回文串是偶数,中心靠右

遍历初始化后的数组 i:1->len-1
[(i - Len[i] + 2) / 2, (i + Len[i] - 2) / 2]
若是字母,可以表示出以此为中心的最长回文串位置
若是‘#’,会出现l>r的情况
*/

/*
qr[i]表示i位置及之前的最长回文子串长度
ql[i]表示i位置及之后的最长回文子串长度
*/
int Len[N], ql[N], qr[N];
char str[N], s[N];
int n, mx, id, len, pos;
void init() {
  int k = 0;
  str[k++] = '$';
  for(int i = 0; i < len; ++i) {
    str[k++] = '#';
    str[k++] = s[i];
  }
  str[k++] = '#';
  len = k;
}
void Manacher() {
  Len[0] = 0; mx = 0;
  for(int i = 1; i < len; ++i) {
    if(i < mx) Len[i] = min(mx-i, Len[2*id-i]);
    else Len[i] = 1;
    while(str[i-Len[i]] == str[i+Len[i]]) Len[i]++;
    if(Len[i] + i > mx) {
      mx = Len[i] + i; id = i;
    }
  }
}
int main() {
  cin >> s;
  len = strlen(s); init();
  Manacher();
  for(int i = 0; i < len; ++i) {
    int l = (i - Len[i] + 2) / 2, r = (i + Len[i] - 2) / 2;
    //检测出‘#’
    if(l > r) continue;
    //更新前缀最长回文子串和后缀最长回文子串
    ql[l] = max(ql[l], r-l+1);
    qr[r] = max(qr[r], r-l+1);
  }
  len = strlen(s);
  for(int i = len-1; i >= 1; --i) ql[i] = max(ql[i], ql[i-1]-2);
  for(int i = 1; i < len; ++i) ql[i] = max(ql[i], ql[i+1]);
  for(int i = len-1; i >= 1; --i) qr[i] = max(qr[i], qr[i+1]-2);
  for(int i = 1; i < len; ++i) qr[i] = max(qr[i], qr[i-1]);
  int ans = 0;
  for(int i = 1; i < len; ++i) ans = max(ans, qr[i]+ql[i+1]);

  cout << ans << endl;
  return 0;
}
发布了28 篇原创文章 · 获赞 14 · 访问量 2958

猜你喜欢

转载自blog.csdn.net/qq_43408978/article/details/103933075
今日推荐