首页 > 其他分享 >Solution - Kilonova 2837 P2

Solution - Kilonova 2837 P2

时间:2024-09-28 21:12:49浏览次数:7  
标签:P2 10 log int lfloor mid rfloor Kilonova 2837

先考虑 q2。

考虑到如果是以 \(2^N\) 为入手点因为进位的原因看起来就做不了。
于是考虑以 \(M\) 为前缀入手。

考虑刻画出 \(M\) 为前缀的数 \(x\) 的形式。
可以考虑根据 \(M\) 后面的位数 \(k\) 来刻画,有 \(x\in \bigcup_{k = 0}^{\lfloor{\frac{L}{\log_2 10}}\rfloor} [M\times 10^k, (M + 1)\times 10^k)\)。

又考虑到判断的是 \(2^N\),于是考虑取 \(\log_2\)。

相当于判断 \(N\) 是否在 \(\bigcup_{k = 0}^{\lfloor{\frac{L}{\log_2 10}}\rfloor} [\log_2 M + k \log_2 10, \log_2 (M + 1) + k \log_2 10)\) 中。

那么因为对于不同的 \(k\) 的区间是无交的,所以可以先让 \(\log_2 M + k\log_2 10\le N\),解出最大的 \(k = \lfloor\frac{N - \log_2 M}{\log_2 10}\rfloor\),再判断 \([N < \log_2 (M + 1) + k\log_2 10]\)。

接下来考虑 q1。

那么相当于是求 \(x\in \bigcup_{k = 0}^{\lfloor{\frac{L}{\log_2 10}}\rfloor} [\log_2 M + k \log_2 10, \log_2 (M + 1) + k \log_2 10)\) 中的最小的整数。

考虑到 \(\log_2 (M + 1) - \log_2 M\le 1\),这说明对于每个 \(k\) 对应的区间里面至多一个整数。

那么此时就需要满足 \(\log_2 M - \lfloor\log_2 M\rfloor + \{k\log_2 10\} \le 1, \log_2 (M + 1) - \lfloor\log_2 M\rfloor + \{k\log_2 10\} > 1(\{x\} = x - \lfloor x\rfloor)\)。
于是就能解出 \(\{k\log_2 10\}\in (1 + \lfloor\log_2 M\rfloor - \log_2 (M + 1), 1 + \lfloor\log_2 M\rfloor - \log_2 M]\)。

同时因为 \(N\in [\log_2 M + k \log_2 10, \log_2 (M + 1) + k \log_2 10)\),所以可以知道 \(N = \lceil\log_2 M + k \log_2 10\rceil\),所以最小化 \(N\) 就是最小化 \(k\)。

于是可以预处理出 \(k\in [0, \lfloor{\frac{L}{\log_2 10}}\rfloor]\) 中的 \(\{k\log 10\}\),并按 \((\{k\log 10\}, k)\) 排序。
然后二分得到 \(\{k\log_2 10\}\) 的范围,线段树查询区间 \(k\) 最小值。

最后考虑 q3。

通过 q1 已经知道了 \(\{k\log_2 10\}\) 的范围。
同时又知道了 \(N = \lceil\log_2 M + k \log_2 10\rceil\),于是可以同样二分求出 \(k\) 的范围。

于是相当于是在 \((\{k\log 10\}, k)\) 处有一个点,查矩形内点的数量。
那么可以预处理建可持久化线段树也可以离线下来扫描线。

时间复杂度 \(\mathcal{O}(L\log L + q\log L)\)。
其中 \(L\) 带个 \(\frac{1}{\log_2 10}\) 的常数,看起来必须带这个常数才能过?

实现用的是可持久化线段树,为了防止一些奇奇怪怪的边界特殊处理了 \(k = 0\) 的情况,同时记得判一下 \(M = 0\) 的情况。

#include<bits/stdc++.h>
inline void Freopen(std::string NAME) {
   freopen((NAME + ".in").c_str(), "r", stdin);
   freopen((NAME + ".out").c_str(), "w", stdout);
}
const double I = log2(10);
inline double getval(double x) {return x - floor(x);}
const int maxL = 1e6 / 3 + 10, LIM = 1e6;
int L, TL;
double l2[LIM + 10], a[maxL];
int id[maxL];
namespace opt1 {
   int mn[maxL * 4];
   void build(int k = 1, int l = 1, int r = L) {
      if (l == r)
         return mn[k] = id[l], void();
      int mid = l + r >> 1;
      build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r);
      mn[k] = std::min(mn[k << 1], mn[k << 1 | 1]);
   }
   int query(int fl, int fr, int k = 1, int l = 1, int r = L) {
      if (fl <= l && r <= fr)
         return mn[k];
      int mid = l + r >> 1, ans = L + 1;
      if (fl <= mid) ans = std::min(ans, query(fl, fr, k << 1, l, mid));
      if (mid < fr) ans = std::min(ans, query(fl, fr, k << 1 | 1, mid + 1, r));
      return ans;
   }
}
namespace opt3 {
   int sum[maxL * 23], ls[maxL * 23], rs[maxL * 23], tot;
   void update(int x, int &k, int lk, int l = 1, int r = L) {
      k = ++tot, sum[k] = sum[lk] + 1, ls[k] = ls[lk], rs[k] = rs[lk];
      if (l == r)
         return ;
      int mid = l + r >> 1;
      if (x <= mid) update(x, ls[k], ls[lk], l, mid);
      else update(x, rs[k], rs[lk], mid + 1, r);
   }
   int query(int fl, int fr, int k, int l = 1, int r = L) {
      if ((! k) || (fl <= l && r <= fr))
         return sum[k];
      int mid = l + r >> 1, ans = 0;
      if (fl <= mid) ans += query(fl, fr, ls[k], l, mid);
      if (mid < fr) ans += query(fl, fr, rs[k], mid + 1, r);
      return ans;
   }
}
int pw[20], rt[maxL];
inline void init() {
   for (int i = pw[0] = 1; i < 20; i++)
      pw[i] = pw[i - 1] << 1;
   for (int i = 1; i <= LIM; i++)
      l2[i] = log2(i);
   for (int i = 1; i <= L; i++)
      a[i] = getval(a[i - 1] + I);
   std::iota(id + 1, id + L + 1, 1);
   std::sort(id + 1, id + L + 1, [&](int x, int y) {
      return a[x] < a[y];
   });
   opt1::build();
   for (int i = 1; i <= L; i++)
      opt3::update(id[i], rt[i], rt[i - 1]);
}
inline double getlog2(int k, int M) {
   return I * k + l2[M];
}
inline int getl(int M) {
   double val = getval(1.0 - getval(l2[M + 1]));
   int l = 1, r = L, w = L + 1;
   while (l <= r) {
      int mid = l + r >> 1;
      if (a[id[mid]] >= val) w = mid, r = mid - 1;
      else l = mid + 1;
   }
   return w;
}
inline int getr(int M) {
   double val = 1.0 - getval(l2[M]);
   int l = 1, r = L, w = -1;
   while (l <= r) {
      int mid = l + r >> 1;
      if (a[id[mid]] <= val) w = mid, l = mid + 1;
      else r = mid - 1;
   }
   return w;
}
inline int getL(int M, int L) {
   int l = 1, r = L, p = L + 1;
   while (l <= r) {
      int mid = l + r >> 1;
      if (getlog2(mid, M) > L) p = mid, r = mid - 1;
      else l = mid + 1;
   }
   return p;
}
inline int getR(int M, int R) {
   int l = 1, r = L, p = 0;
   while (l <= r) {
      int mid = l + r >> 1;
      if (getlog2(mid, M) <= R) p = mid, l = mid + 1;
      else r = mid - 1;
   }
   return p;
}
inline void solve() {
   int opt, M; scanf("%d%d", &opt, &M);
   if (opt == 1) {
      for (int i = 0; i < 20; i++)
         if (pw[i] == M)
            return printf("%d\n", i), void();
      int k = opt1::query(getl(M), getr(M));
      printf("%.0lf\n", ceil(getlog2(k, M)));
   } else if (opt == 2) {
      int N; scanf("%d", &N);
      if (M == 0)
         return puts("0"), void();
      int k = floor((N - l2[M]) / I);
      puts(getlog2(k, M) <= N && N < getlog2(k, M + 1) ? "1" : "0");
   } else {
      int A, B; scanf("%d%d", &A, &B);
      if (M == 0)
         return puts("0"), void();
      int ans = 0;
      for (int i = 0; i < 20; i++)
         ans += pw[i] == M && A <= i && i <= B;
      int fl = getl(M), fr = getr(M);
      int kl = getL(M, A - 1), kr = getR(M, B);
      if (fl <= fr && kl <= kr)
         ans += opt3::query(kl, kr, rt[fr]) - opt3::query(kl, kr, rt[fl - 1]);
      printf("%d\n", ans);
   }
}
int main() {
   Freopen("p2");
   int Q; scanf("%d%d", &Q, &L);
   L /= 3, L++;
   init();
   for (; Q--; )
      solve();
   return 0;
}

标签:P2,10,log,int,lfloor,mid,rfloor,Kilonova,2837
From: https://www.cnblogs.com/rizynvu/p/18438371

相关文章

  • 树莓派pico rp2040 使用rust 在ssd1306上显示中文信息
    在rp2040上用DHT22+ssd1306显示温度信息, 用embedded-graphics库和ssd1306库来实现。但实现的效果不是很理想,无法在ssd1306屏幕上显示中文。 为了解决这个问题,在github和crates.io上面找了几天。解决方法还是找到了,利用 u8g2-font这个库实现。。。 实现的办法如下:Car......
  • WINCCV7.5SP2VBA编程8-通过事件执行脚本
    这一篇在新浪博客发表过,审核周期有点长,为了避免丢失,这里再记录一遍。有三种途径执行Wincc画面设计器的VBA脚本:事件、用户自定义菜单和工具栏、VBA编辑器。前面的学习是通过VBA编辑器执行的VBA程序,现在通过事件来练习VBA程序执行。还是在前面WINCC项目程序来做练习。打开项目编......
  • NOIP2024集训Day37 DP
    NOIP2024集训Day37DPA.[CQOI2011]放棋子设\(f_{i,j,k}\)表示前\(k\)种棋子放了任意\(i\)行、\(j\)列。决策是:在哪些位置填同种颜色的棋子。于是美剧上一个状态的\(i,j\)(表示为\(l,r\)),上一状态\(k_1=k-1\)。设\(g_{i,j,k}\)表示\(k\)个同种颜色的......
  • [NOIP2017 提高组] 奶酪 题解
    题目背景NOIP2017提高组D2T1题目描述现有一块大奶酪,它的高度为 h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为 z=0,奶酪的上表面为 z=h。现在,奶酪的下表面有一只小老鼠Jerry,......
  • Wincc7.5sp2使用VBA6-全局模板、项目模板和页面模板
    这一篇博客在新浪发表过,那边还在审核,为了避免关闭服务,在这里再次发一遍。那边的博客发表后审核期间,如果想修改是不允许的,审核时间比较长,有点不合理。前面的VBA练习,都是针对具体的项目的具体画面进行编程,在wincc项目还可以全局VBA编程和具体项目VBA编程。我边看技术文档边做练习,......
  • 【2024.09.27】NOIP2024 赛前集训-刷题训练(3)
    【2024.09.27】NOIP2024赛前集训-刷题训练(3)「NOIP2018提高组」铺设道路算法一:模拟正常人铺路的过程,每次找区间的最小值,最小值就是本次填的高度,由于出现了若干个0位置,就分裂成若干个子区间去重复上述过程,直到全部变成0。时间复杂度\(O(nlogn)\),瓶颈在预处理st表。算法二:若......
  • CSP2024-27
    2A题意:1A题意:给定\(n\timesn\)种物品,\((i,j)\)有\(a_{i,j}\)个,权值为\(b_{i,j}\),两个物品等价当且仅当\(i\)相等或\(j\)相等。初始有一个空(可重)集\(S\),每次等概率从剩余物品中选一个\(x\)出来。如果\(S\)中没有和\(x\)等价的物品,那么\(x\)加入\(S\)......
  • NOIP2024模拟测试赛(一)
    比赛链接A.tree当\(\forallv_i\le1\)时,可以直接从下往上贪心选,一个以\(u\)为根的子树中联通块如果权值和\(>k\)那么肯定能删到恰好\(k\)。否则的话就把这个联通块并到\(u\)父亲上再看就行。当\(\forallv_i\le2\)时,直接贪心可能有问题,大于\(k\)的权值和可能......
  • 【题解】【归并排序】—— [NOIP2011 普及组] 瑞士轮
    【题解】【归并排序】——[NOIP2011普及组]瑞士轮[NOIP2011普及组]瑞士轮题目背景题目描述输入格式输出格式输入输出样例输入#1输出#1提示1.思路解析2.AC代码[NOIP2011普及组]瑞士轮通往洛谷的传送门题目背景在双人对决的竞技性比赛,如乒乓球、羽毛球、......
  • P2090 数字对
    P2090数字对不是,这不是黄题吗,鉴定为我太菜了考虑这东西长得像辗转相除法。最终结果一定是\((n,B)\)这样子的。那么它一定是由\((n-B,B)\)转移过来。对于\((a,b)\)如果\(a>b\)它会变成\((a-b,b)\),否则是\((a,b-a)\)。于是也许我们可以枚举\(B\),把\(a-b\)这个操作......