逐月信息学 2024 提高组 #6

\(\color{black}\texttt{A. 数字涡旋}\)

题目描述

有一张无线大的表格,里面填着所有正整数,表格如下:

\[\begin{matrix} 1&2&9&\dots\\ 4&3&8\\ 5&6&7\\ \vdots&&&\ddots \end{matrix} \]

求数字 \(N\) 出现在表格的几行几列。

思路

推式子体。

空间复杂度 \(O(1)\),时间复杂度 \(O(T)\)

代码

#include<bits/stdc++.h>
using namespace std;

int t, n, k;

int Sqrt(int x) {
  int l = 1, r = 31624;
  for(; l < r; ) {
    int mid = (l + r) >> 1;
    (1ll * mid * mid >= x ? r = mid : l = mid + 1);
  }
  return l;
}

void Solve() {
  cin >> n;
  k = Sqrt(n);
  int d = k * k - n;
  if(k % 2 == 0) {
    if(d < k) {
      cout << k << " " << 1 + d << "\n";
    }else {
      cout << k - (d - k + 1) << " " << k << "\n";
    }
  }else {
    if(d < k) {
      cout << 1 + d << " " << k << "\n";
    }else {
      cout << k << " " << k - (d - k + 1) << "\n";
    }
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(cin >> t; t--; Solve()) {
  }
  return 0;
}

\(\color{black}\texttt{B. 潦草急就}\)

题目描述

\(0\)\(N\) 之间在 \(K\) 进制下数字 \(0\)\(K-1\) 分别出现了多少次(不包括前导零)。

思路

还是找规律,但是更难了些。

按位枚举即可。也可以用差分优化。

空间复杂度 \(O(K)\),时间复杂度 \(O(T(K+\log_K N))\)

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAXK = 17, MOD = 2027;

int t, k;
ll n, ans[MAXK];

void Solve() {
  cin >> n >> k;
  for(int i = 0; i < k; ++i) {
    ans[i] = 0;
  }
  n++;
  for(ll i = 1; i <= n; i *= k) {
    ans[0] = (ans[0] + 1ll * n / (i * k) * i);
    ans[0] = (ans[0] + i);
    ans[n % (i * k) / i] = (ans[n % (i * k) / i] - i + n % (i * k) % i);
    ans[n % (i * k) / i + 1] -= n % (i * k) % i;
    ans[0] = (ans[0] - min(n, i));
    ans[1] = (ans[1] + min(n, i));
  }
  cout << (ans[0] + 1) % MOD << " ";
  for(int i = 1; i < k; ++i) {
    ans[i] = (ans[i] + ans[i - 1]);
    cout << ans[i] % MOD << " \n"[i == k - 1];
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(cin >> t; t--; Solve()) {
  }
  return 0;
}

\(\color{black}\texttt{C. 柳暗花明}\)

题目描述

给定一个序列 \(A\)\(Q\) 次询问,令 \(f_x(l,r)=\begin{cases}x&l>r\\\lfloor\frac{f_x(l,r-1)+A_r}{2}\rfloor&l\le r\end{cases}\),求对于每次询问求 \(f_x(l,r)\) 的值。

思路

首先看这些数对答案的贡献:假设选择 \([l,r],x\),则 \(f_x(l,r)\le \frac{\frac{\frac{\frac{x+A_l}{2}+A_{l+1}}{2}+\dots}{2}+A_r}{2}=\frac{x}{2^{r-l+1}}+\frac{A_l}{2^{r-l+1}}+\frac{A_{l+1}}{2^{r-l}}+\dots+\frac{A_r}{2}\),可以发现,前面很多的部分对答案的贡献微乎其微,向下取整后直接消失,所以实际上只需计算后 \(100\) 个数即可。

空间复杂度 \(O(N)\),时间复杂度 \(O(Q)\)

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 200001;

int n, a[MAXN], q;

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
  }
  cin >> q;
  for(int i = 1, x, l, r; i <= q; ++i) {
    cin >> x >> l >> r;
    for(int j = max(l, r - 100); j <= r; ++j) {
      x = (x + a[j]) / 2;
    }
    cout << x << "\n"; 
  }
  return 0;
}

\(\color{black}\texttt{D. 移动硬币}\)

题目描述

\(N\) 种硬币,每种硬币的面额为 \(w_i\),并且每种硬币都有 \(1145141919810!^{1145141919810!^{1145141919810!^{\dots^{1145141919810!}}}}\}1145141919810!\) 个,求能凑出多少种不同且 \(\le L\) 的钱数。

思路

首先对 \(w\) 排序。考虑能凑出最小的钱数 \(x\) 使 \(x\equiv i\pmod {w_n}(0\le i< w_n)\),只要凑出这些钱,那么不断再用 \(w_n\) 即可。这些数 \(\mod w_n\) 不同,值也必定不同。而求最少钱数可以用同余最短路解决。

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAXN = 1000001;
const ll INF = LLONG_MAX;

struct Node {
  int x;
  ll dis;
};

struct cmp {
  bool operator()(const Node &a, const Node &b) const {
    return a.dis > b.dis;
  }
};

int n, w[MAXN];
ll dist[MAXN];
bool vis[MAXN];
ll l, ans;
priority_queue<Node, vector<Node>, cmp> pq;

void Record(int u, ll dis) {
  if(dis >= dist[u]) {
    return;
  }
  dist[u] = dis;
  pq.push({u, dis});
}

void dij() {
  fill(dist, dist + w[1], INF);
  Record(0, 0);
  for(; !pq.empty(); ) {
    auto [u, dis] = pq.top();
    pq.pop();
    if(vis[u]) {
      continue;
    }
    vis[u] = 1;
    for(int i = 2; i <= n; ++i) {
      Record((u + w[i]) % w[1], dis + w[i]);
    }
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> l;
  for(int i = 1; i <= n; ++i) {
    cin >> w[i];
  }
  dij();
  for(int i = 0; i < min(l, 0ll + w[1]); ++i) {
    if(dist[i] <= l) {
      ans += (l - dist[i]) / w[1] + 1;
    }
  }
  cout << ans - 1;
  return 0;
}
posted @ 2024-07-05 16:26  Yaosicheng124  阅读(4)  评论(0编辑  收藏  举报