2022牛客多校补题2

D

img
img

思路

img
主要是转化为log不太容易能想到

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define int ll
#define Max 0x3f3f3f3f
#define Min 0x0c0c0c0c0;
using vi = vector<int>;
using pii = pair<int, int>;
using vpii = vector<pii>;
using vvi = vector<vector<int>>;
const int N = 1e3 + 10;
int h[N], e[N << 1], ne[N << 1], idx, ti[N];
double v[N << 1], dis[N];
bool st[N];
int n, m;

void add(int a, int b, double c) {
  e[idx] = b, ne[idx] = h[a], v[idx] = c, h[a] = idx++;
}

bool check(long double w) {
  double power = log(w);
  queue<int> q;
  for (int i = 1; i <= n; i++)
    dis[i] = 0, q.push(i), st[i] = 1, ti[i] = 1;
  while (!q.empty()) {
    int u = q.front();
    st[u] = 0;
    q.pop();
    if (ti[u] > n)
      return 0;
    for (int j = h[u]; ~j; j = ne[j]) {
      int to = e[j];
      if (dis[to] < dis[u] + v[j] + power) {
        dis[to] = dis[u] + v[j] + power;
        if (!st[to]) {
          q.push(to);
          st[to] = 1;
          ti[to] = ti[u] + 1;
        }
      }
    }
  }
  return 1;
}
void sol() {
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    add(b, d, log((double)c / a));
  }
  long double r = 1, l = 0;

  while (r - l > 1e-9) {
    long double mid = (r + l) / 2;
    if (check(mid)) {
      l = mid;
    } else
      r = mid;
  }
  cout << fixed << setpre
}
signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  int t;
  memset(h, -1, sizeof h);
  t = 1;
  while (t--)
    sol();
}

G

img
img

思路

打表找规律,可以发现将数组合之后最长上升子序列和最长下降子序列长度是$$\sqrt{n}$$

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        int x = ceil(sqrt(n)), p = n, o = 0;
        while (p >= 0)
        {
            for (int i = p - x + 1; i <= p; i++)
                if (i > 0)
                    cout << i << ' ';
            p -= x;
        }
        cout << endl;
    }
    return 0;
}

K

img
img

思路

这道题主要是状态表示很难想
dp[i][j][k] 表示b的前i位中,与a的lcs为j,左括号比右括号多k个的方案数
显然j的最大值就是子序列a的长度

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
int dp[205][205][205];
char s[205];
const int N = 1e9 + 7;
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        int n, m;
        cin >> n >> m;
        cin >> s + 1;
        for (int i = 0; i <= m; i++)
            for (int j = 0; j <= n; j++)
                for (int k = 0; k <= m; k++)
                    dp[i][j][k] = 0;
        dp[0][0][0] = 1;
        for (int i = 1; i <= m; i++)
        {
            for (int j = 0; j <= n; j++)
            {
                for (int k = 0; k <= m; k++)
                {
                    //如果b的第i位要放左括号
                    dp[i][j + (s[j + 1] == '(')][k + 1] += dp[i - 1][j][k];
                    dp[i][j + (s[j + 1] == '(')][k + 1] %= N;
                    if (k)//如果前面已经有多的左括号才可以放右括号
                        {
                            如果b的第i位要放右括号
                            dp[i][j + (s[j + 1] == ')')][k - 1] += dp[i - 1][j][k];
                            dp[i][j + (s[j + 1] == ')')][k - 1] %= N;
                        }
                }
            }
        }
        cout << dp[m][n][0] << endl;
    }
    return 0;
}
posted @ 2022-07-31 14:45  Sun-Wind  阅读(23)  评论(0编辑  收藏  举报