LOJ #6432. 「PKUSC2018」真实排名(组合数)

题面

LOJ #6432. 「PKUSC2018」真实排名

注意排名的定义 , 分数不小于他的选手数量 !!!

题解

有点坑的细节题 ...

思路很简单 , 把每个数分两种情况讨论一下了 .

假设它为 x .

  1. 不对它进行翻倍操作 :

    那么很容易发现 [x2,x) 的数都不翻倍 . 其余部分任意 . 假设有 tot 个 .

    那么这部分答案就是 (ntot1k) .

    1 因为它本身不能操作 .

  2. 对它进行翻倍操作 :

    那么又是显然的 , [x,2x) 的所有数都需要翻倍 . 其余部分任意 . 假设这段有 tot 个 .

    那么这部分答案就是 (ntotktot) .

然后当 x=0 的时候需要特殊判断 , 我们可以随意翻倍都不改变结果了 , 答案就是 (nk) .

查询 [l,r] 中数字的个数 , 有个巧妙的操作 . 此处 a 是排好序的

inline int Sum(int l, int r) { if (l > r) return 0; return upper_bound(a + 1, a + 1 + n, r) - lower_bound(a + 1, a + 1 + n, l); }

以后做这种题一定不能偷懒 , 用脑子想 , 而是要用笔去写 , 把每种情况写清楚了 !!!

那样并不浪费时间 , 反而节省时间 !!

代码

#include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Set(a, v) memset(a, v, sizeof(a)) using namespace std; inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;} inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() { int x = 0, fh = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1; for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48); return x * fh; } void File() { #ifdef zjp_shadow freopen ("6432.in", "r", stdin); freopen ("6432.out", "w", stdout); #endif } const int N = 1e5 + 1e3, Mod = 998244353; int n, k, a[N], b[N]; typedef long long ll; ll fac[N], ifac[N]; ll fpm(ll x, ll power) { ll res = 1; x %= Mod; for (; power; power >>= 1, (x *= x) %= Mod) if (power & 1) (res *= x) %= Mod; return res; } ll C(int n, int m) { if (n < 0 || m < 0 || n < m) return 0; return fac[n] * ifac[m] % Mod * ifac[n - m] % Mod; } void Init(int maxn) { fac[0] = ifac[0] = 1; For (i, 1, maxn) fac[i] = fac[i - 1] * i % Mod; ifac[maxn] = fpm(fac[maxn], Mod - 2); Fordown (i, maxn - 1, 1) ifac[i] = ifac[i + 1] * (i + 1) % Mod; } inline int Sum(int l, int r) { if (l > r) return 0; return upper_bound(a + 1, a + 1 + n, r) - lower_bound(a + 1, a + 1 + n, l); } int main () { File(); Init(1e5); n = read(); k = read(); For (i, 1, n) a[i] = b[i] = read(); sort(a + 1, a + 1 + n); For (i, 1, n) { if (!b[i]) { printf ("%lld\n", C(n, k)); continue ; } ll res = C(n - Sum((b[i] + 1) / 2, b[i] - 1) - 1, k); int tot = Sum(b[i], b[i] * 2 - 1); (res += C(n - tot, k - tot)) %= Mod; printf ("%lld\n", res); } return 0; }

__EOF__

本文作者zjp_shadow
本文链接https://www.cnblogs.com/zjp-shadow/p/9141804.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zjp_shadow  阅读(482)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示